前言
本文整理并总结了十大经典的排序算法(冒泡排序、选择排序、插入排序、快速排序、归并排序、希尔排序、计数排序、基数排序、桶排序、堆排序)的时间复杂度、空间复杂度等性质。
本文并不会详细讲解每种排序算法的原理,网上有很多很好的教程,大家可以自己去搜了看。
最后我还亲自手写了十种排序算法的 c++ 代码,大家可以用来通过 LeetCode 912. 排序数组[1] 这道题。
性质汇总
如果发现图中有错误,请留言告知。
十大经典排序算法性质汇总
维基百科
我觉得还是英文维基百科讲的比较详细、严谨。如果大家看的比较累的话,可以自己百度搜索相应的教程。
冒泡排序
https://en.wikipedia.org/wiki/Bubble_sort
选择排序
https://en.wikipedia.org/wiki/Selection_sort
插入排序
https://en.wikipedia.org/wiki/Insertion_sort
快速排序
https://en.wikipedia.org/wiki/Quicksort
归并排序
https://en.wikipedia.org/wiki/Merge_sort
希尔排序
https://en.wikipedia.org/wiki/Shellsort
计数排序
https://en.wikipedia.org/wiki/Counting_sort
基数排序
https://en.wikipedia.org/wiki/Radix_sort
桶排序
https://en.wikipedia.org/wiki/Bucket_sort
堆排序
https://en.wikipedia.org/wiki/Heapsort
代码实现
所有的排序算法接口都是相同的,也就是 vector xxxSort(vector& nums)
。只需要你传入一个 vector
类型的数组,就能返回排序后的结果。
运行下来可以发现,桶排序速度是比较快的。而冒泡排序、选择排序和插入排序因为时间复杂度太高无法通过本题,基数排序因为无法处理负数也不能通过本题。
classSolution { public: vector<int>sortArray(vector<int>&nums) { returnquickSort(nums); } // 冒泡排序(超时)vector<int>bubbleSort(vector<int>&nums) { intn=nums.size(); for (inti=0; i<n; ++i) { for (intj=n-2; j>=i; --j) { if (nums[j] >nums[j+1]) { swap(nums[j], nums[j+1]); } } } returnnums; } // 选择排序(超时)vector<int>selectSort(vector<int>&nums) { intn=nums.size(); for (inti=0; i<n; ++i) { intidx=i; for (intj=i; j<n; ++j) { if (nums[j] <nums[idx]) { idx=j; } } swap(nums[i], nums[idx]); } returnnums; } // 插入排序(超时) vector<int>insertSort(vector<int>&nums) { intn=nums.size(); for (inti=0; i<n; ++i) { for (intj=i; j>0&&nums[j] <nums[j-1]; --j) { swap(nums[j], nums[j-1]); } } returnnums; } // 快速排序(24 ms) voidqSort(vector<int>&nums, intl, intr) { if (l>=r) return; intm=l; for (inti=l; i<r; ++i) { if (nums[i] <nums[r]) { swap(nums[m++], nums[i]); } } swap(nums[m], nums[r]); qSort(nums, l, m-1); qSort(nums, m+1, r); } vector<int>quickSort(vector<int>&nums) { intn=nums.size(); qSort(nums, 0, n-1); returnnums; } // 归并排序(192 ms)vector<int>mSort(vector<int>&nums, intl, intr) { if (l>=r) return {nums[l]}; intm=l+(r-l)/2; vector<int>lnums=mSort(nums, l, m); vector<int>rnums=mSort(nums, m+1, r); vector<int>res; inti=0, j=0; while (i<=m-l&&j<=r-m-1) { if (lnums[i] <rnums[j]) { res.push_back(lnums[i++]); } else { res.push_back(rnums[j++]); } } while (i<=m-l) { res.push_back(lnums[i++]); } while (j<=r-m-1) { res.push_back(rnums[j++]); } returnres; } vector<int>mergeSort(vector<int>&nums) { intn=nums.size(); nums=mSort(nums, 0, n-1); returnnums; } // 归并排序 + 非递归(80 ms)vector<int>mergeSortNR(vector<int>&nums) { intn=nums.size(); for (intlen=1; len<n; len<<=1) { for (intl=0; l<n-len; l+=2*len) { intm=l+len-1; intr=min(n-1, l+2*len-1); vector<int>res; inti=l, j=m+1; while (i<=m&&j<=r) { if (nums[i] <nums[j]) { res.push_back(nums[i++]); } else { res.push_back(nums[j++]); } } while (i<=m) { res.push_back(nums[i++]); } while (j<=r) { res.push_back(nums[j++]); } for (inti=l; i<=r; ++i) { nums[i] =res[i-l]; } } } returnnums; } // 希尔排序(40 ms)vector<int>shellSort(vector<int>&nums) { intn=nums.size(); for (intgap=n/2; gap>0; gap/=2) { for (inti=gap; i<n; ++i) { for (intj=i; j-gap>=0&&nums[j-gap] >nums[j]; j-=gap) { swap(nums[j-gap], nums[j]); } } } returnnums; } // 计数排序(32 ms) vector<int>countSort(vector<int>&nums) { intn=nums.size(); if (!n) return {}; intminv=*min_element(nums.begin(), nums.end()); intmaxv=*max_element(nums.begin(), nums.end()); intm=maxv-minv+1; vector<int>count(m, 0); for (inti=0; i<n; ++i) { count[nums[i]-minv]++; } vector<int>res; for (inti=0; i<m; ++i) { for (intj=0; j<count[i]; ++j) { res.push_back(i+minv); } } returnres; } // 基数排序(不适用于负数) vector<int>radixSort(vector<int>&nums) { intn=nums.size(); intmaxv=*max_element(nums.begin(), nums.end()); intmaxd=0; while (maxv>0) { maxv/=10; maxd++; } vector<int>count(10, 0), rank(n, 0); intbase=1; while (maxd>0) { count.assign(10, 0); for (inti=0; i<n; ++i) { count[(nums[i]/base)%10]++; } for (inti=1; i<10; ++i) { count[i] +=count[i-1]; } for (inti=n-1; i>=0; --i) { rank[--count[(nums[i]/base)%10]] =nums[i]; } for (inti=0; i<n; ++i) { nums[i] =rank[i]; } maxd--; base*=10; } returnnums; } // 桶排序 (20 ms) vector<int>bucketSort(vector<int>&nums) { intn=nums.size(); intmaxv=*max_element(nums.begin(), nums.end()); intminv=*min_element(nums.begin(), nums.end()); intbs=1000; intm= (maxv-minv)/bs+1; vector<vector<int>>bucket(m); for (inti=0; i<n; ++i) { bucket[(nums[i]-minv)/bs].push_back(nums[i]); } intidx=0; for (inti=0; i<m; ++i) { intsz=bucket[i].size(); bucket[i] =quickSort(bucket[i]); for (intj=0; j<sz; ++j) { nums[idx++] =bucket[i][j]; } } returnnums; } // 堆排序(32 ms) voidadjust(vector<int>&nums, intp, ints) { while (2*p+1<s) { intc1=2*p+1; intc2=2*p+2; intc= (c2<s&&nums[c2]>nums[c1]) ?c2 : c1; if (nums[c] >nums[p]) swap(nums[c], nums[p]); elsebreak; p=c; } } vector<int>heapSort(vector<int>&nums) { intn=nums.size(); for (inti=n/2-1; i>=0; --i) { adjust(nums, i, n); } for (inti=n-1; i>0; --i) { swap(nums[0], nums[i]); adjust(nums, 0, i); } returnnums; } };
参考资料
[1]
LeetCode 912. 排序数组: https://leetcode-cn.com/problems/sort-an-array/
作者简介:godweiyang,知乎同名,华东师范大学计算机系硕士在读,方向自然语言处理与深度学习。喜欢与人分享技术与知识,期待与你的进一步交流~