十大经典排序算法整理汇总(附代码)

简介: 本文整理并总结了十大经典的排序算法(冒泡排序、选择排序、插入排序、快速排序、归并排序、希尔排序、计数排序、基数排序、桶排序、堆排序)的时间复杂度、空间复杂度等性质。

前言


本文整理并总结了十大经典的排序算法(冒泡排序、选择排序、插入排序、快速排序、归并排序、希尔排序、计数排序、基数排序、桶排序、堆排序)的时间复杂度、空间复杂度等性质。

本文并不会详细讲解每种排序算法的原理,网上有很多很好的教程,大家可以自己去搜了看。

最后我还亲自手写了十种排序算法的 c++ 代码,大家可以用来通过 LeetCode 912. 排序数组[1] 这道题。

性质汇总


如果发现图中有错误,请留言告知。

image.png十大经典排序算法性质汇总

维基百科


我觉得还是英文维基百科讲的比较详细、严谨。如果大家看的比较累的话,可以自己百度搜索相应的教程。

冒泡排序

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/

image.png

作者简介:godweiyang知乎同名华东师范大学计算机系硕士在读,方向自然语言处理与深度学习喜欢与人分享技术与知识,期待与你的进一步交流~

相关文章
|
开发框架 搜索推荐 算法
C#经典十大排序算法(完结)
C#经典十大排序算法(完结)
|
算法 机器人 调度
降维打击,offer拿到吐!字节跳动算法大佬工作笔记整成算法宝典
前言 算法,一个听起来高深又晦涩的概念,仿佛逐渐支配了我们日常生活的方方面面,依托这个概念而衍生出的工作行业,也逐渐成为兼具“前途”与“钱途”的香饽饽。 其实要搞清楚“算法”为什么值钱,看看我们的日常生活就知道。从早上出门打车用的打车软件、导航软件,上班用的电脑、文件和在线工具,点外卖咖啡的App(应用程序)和快递调度,到手机支付,孩子上的网课,在淘宝、京东购物,看微信,刷抖音,用语音助手,和机器人聊天,这些行为背后全是强大的算法在操纵。 未来是人和机器一起仰望星空的时代,而算法是打开未来世界的钥匙。普通人需要深度了解算法吗?答案当然是肯定的。或许你已经听倦了“我们生活在算法操控的时代”这
84 0
腾讯T3算法大牛整理分享的LeetCode算法小抄完整文档
本文⽬前可以⼿把⼿带你解决 110 道 LeetCode 算法问题,⽽且在不断更新,全部基于 LeetCode 的题⽬,涵盖了所有题型和技巧。
|
算法 大数据 程序员
膜拜!字节跳动算法国内第一人亲撰:数据结构与算法全解笔记
近些年来,算法在互联网的地位占重凸显,在各大互联网企业应用中有着举足轻重的作用。无论是面试还是笔试,算法都占据着绝大部分。 而即将到来的 金九银十”正是跳槽涨薪的最佳时机! 最近我针对各家名企IT面试知识点方面进行了总结。对当前程序员面试缺乏权威题目进行汇总,应对即将到来的金九银十。在此,给大家带来571页经典算法面试题,希望对大家有所帮助。
|
搜索推荐 C++
十大经典排序算法整理汇总(附代码)
十大经典排序算法整理汇总(附代码)
|
机器学习/深度学习 自然语言处理 算法
graphSage还是HAN ?吐血力作综述Graph Embeding 经典好文
graphSage还是HAN ?吐血力作综述Graph Embeding 经典好文
graphSage还是HAN ?吐血力作综述Graph Embeding 经典好文
|
搜索推荐 算法
九大经典排序算法(王道考研排序算法整理)
九大经典排序算法(王道考研排序算法整理)
167 0
九大经典排序算法(王道考研排序算法整理)
|
算法 搜索推荐 Shell
【数据结构与算法】之十大经典排序算法(上)
【数据结构与算法】之十大经典排序算法(上)
122 0
【数据结构与算法】之十大经典排序算法(上)
|
存储 移动开发 算法
【数据结构与算法】之十大经典排序算法(下)
【数据结构与算法】之十大经典排序算法(下)
【数据结构与算法】之十大经典排序算法(下)
|
存储 机器学习/深度学习 算法
【算法攻坚】算法刷题开篇
单词表中的abandon 万事开头难,现在就从单词第一个入手,这道本身也不难,所以就从他开始了 two sum
110 0
下一篇
无影云桌面