爆肝整理!堪称全网最详细的十大常用经典排序算法总结!!!

写在开头,本文经过参考多方资料整理而成,全部参考目录会附在文章末尾。很多略有争议性的细节都是在不断查阅相关资料后总结的,具有一定普适性。

总表:

相关解释:

稳定:如果原本序列中a在b前面且a=b,排序后a仍在b前面,顺序不变;

不稳定:如果原本序列中a在b前面且a=b,排序后a可能在b后面,顺序可能发生改变;

内排序:所有排序操作均在内存中完成;

外排序:由于数据量太大,将其放入磁盘中,排序过程中需要磁盘与内存之间的数据传输;

时间复杂度:一个排序算法在执行过程中所耗费的时间量级的度量;

空间复杂度:一个排序算法在运行过程中临时占用存储空间大小的度量;

附加:

本表格已上传至个人资源,并设置了1积分下载(欢迎支持啦!!),有需要的朋友可以自取;

该表格已同步上传至网盘,附网盘下载链接:

链接:https://pan.baidu.com/s/1Ov7yFpZnbQy1cf_fBCGyEA 
提取码:p400

规律性记忆:

归纳总结:

1. 稳定性记忆方法——“快希选堆”不稳定。

2. 需要使用额外空间的四种排序——基数、计数、桶排、归并。

3. 常用时间复杂度大小关系:O(1)<O(logn)<O(n)<O(n logn)<O(n²)<O(n³)<O(2^n)<O(n!)<O(n^n)。

4. 空间复杂度为O(1) 的排序:冒泡、插入、选择、希尔、堆排;

5. 时间复杂度最优情况可达O(n)的排序:冒泡、插入、桶排;

6. 最优、平均、最差时间复杂度一致的排序:选择、堆排、归并、基数、计数;

7. 最差情况下时间复杂度仍为O(n logn)的排序:堆排、归并;

8. 最差情况下时间复杂度仍在线性时间范围内的排序:计数;

排序方法选取规则:

1. 如果待排序列中数据含有大量重复值——优先使用计数排序;

2. 如果待排序列中数据近乎有序——优先使用插入排序;

3. 如果待排序列中数据取值范围有限——优先使用计数排序;

4. 如果待排序列中数据要求稳定——优先使用归并排序;

5. 如果待排序列需要使用链表——优先链表归并、链表快排;

6. 如果待排序列中数据无法全部装到内存——优先使用外部排序;

十大排序算法详解:

一、冒泡排序(Bubble Sort)

遍历所有的数据,每次对相邻元素进行两两比较,如果顺序和预先规定的顺序不一致,则进行位置交换;这样一次遍历会将最大或最小的数据上浮到顶端,之后再重复同样的操作,直到所有的数据有序。数据是反序时,耗费时间最长O(n²);数据是正序时,耗费时间最短O(n)。

平均时间复杂度为O(n²),空间复杂度为O(1),是一种稳定的排序算法。

附算法实现源码:

//冒泡排序
template <class T>
void BubbleSort(T data[],int n)
{int flag=0;for(int i=0;i<n;i++){flag=0;for(int j=1;j<n-i;j++){if(data[j]<data[j-1]){flag=1;T t=data[j];data[j]=data[j-1];data[j-1]=t;}}if(flag==0)return;}
}

二、快速排序(Quick Sort)

快速排序采用分治法。首先从数列中挑出一个元素作为中间值。依次遍历数据,所有比中间值小的元素放在左边,所有比中间值大的元素放在右边。然后按此方法对左右两个子序列分别进行递归操作,直到所有数据有序。最理想的情况是,每次划分所选择的中间数恰好将当前序列几乎等分(均匀排布),整个算法的时间复杂度为O(n logn)。 最坏的情况是,每次所选的中间数是当前序列中的最大或最小元素(正序和逆序都是最坏),整个排序算法的时间复杂度为O(n²)。

平均时间复杂度为O(n logn),空间复杂度为O(logn),是一种不稳定的排序算法。

附算法实现源码:

//快速排序
template <class T>
int Partition(T data[],int left,int right)
{T pivot=data[left];while(left<right){while(left<right&&data[right]>pivot)right--;data[left]=data[right];while(left<right&&data[left]<=pivot)left++;data[right]=data[left];}data[left]=pivot;return left;
}template <class T>
void QuickSort(T data[],int left,int right)
{if(left<right){int p=Partition(data,left,right);QuickSort(data,left,p-1);QuickSort(data,p+1,right);}}

三、选择排序(Selection Sort)

遍历所有数据,先在数据中找出最大或最小的元素,放到序列的起始;然后再从余下的数据中继续寻找最大或最小的元素,依次放到序列中直到所有数据有序。原始数据的排列顺序不会影响程序耗费时间O(n²),相对费时,不适合大量数据排序。

平均时间复杂度为O(n²),空间复杂度为O(1),是一种不稳定的排序算法。

附算法实现源码:


//选择排序
template <class T>
void SelectionSort(T data[],int n)
{for(int i=1;i<n;i++){int k=i-1;for(int j=i;j<n;j++){if(data[j]<data[k]){k=j;}}if(k!=i-1){T t=data[k];data[k]=data[i-1];data[i-1]=t;}}
}

四、插入排序(Insertion Sort)

将前i个(初始为1)数据假定为有序序列,依次遍历数据,将当前数据插入到前述有序序列的适当位置,形成前i+1个有序序列,依次遍历完所有数据,直至序列中所有数据有序。数据是反序时,耗费时间最长O(n²);数据是正序时,耗费时间最短O(n)。适用于部分数据已经排好的少量数据排序。

平均时间复杂度为O(n²),空间复杂度为O(1),是一种稳定的排序算法。

附算法实现源码(直接插入+折半插入):

//直接插入排序
template <class T>
void InsertionSort(T Data[],int n)
{int p,i;for(p=1;p<n;p++){T temp=Data[p];i=p-1;while(i>=0&&Data[i]>temp){Data[i+1]=Data[i];i--;}Data[i+1]=temp;}
}//折半插入排序
template <class T>
void BinaryInsertionSort(T Data[],int n)
{int left,mid,right,p;for(p=1;p<n;p++){T temp=Data[p];left =0;right=n-1;while(left<=right){mid=(left+right)/2;if(Data[mid]>temp)right=mid-1;elseleft=mid+1;}for(int i=p-1;i>=left;i--)Data[i+1]=Data[i];Data[left]=temp;}
}

五、希尔排序(Shell Sort)

希尔排序也称递减增量排序,是对插入排序的改进,以牺牲稳定性的方法提高效率。基本思路是先将整个数据序列分割成若干子序列分别进行直接插入排序,待整个序列中的记录基本有序时,再对全部数据进行依次直接插入排序,直至所有数据有序。希尔排序算法的性能与所选取的分组长度序列有很大关系,复杂度下界为O(n log²n),在中等规模的数据中表现良好。

平均时间复杂度为O(n^3/2),空间复杂度为O(1),是一种不稳定的排序算法。

附算法实现源码:

//希尔排序
template <class T>
void ShellSort(T Data[],int n)
{int d=n/2;while(d>=1){for(int k=0;k<d;k++){for(int i=k+d;i<n;i+=d){T temp=Data[i];int j=i-d;while(j>=k&&Data[j]>temp){Data[j+d]=Data[j];j-=d;}Data[j+d]=temp;}}d=d/2;}
}

六、堆排序(Heap Sort)

堆排序利用堆这种近似完全二叉树的数据结构进行排序。堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。以最大堆为例,堆中的最大值总是位于根节点。首先将待排序的n个数据构造为大根堆,将顶端数据与末尾数据进行交换并将堆的尺寸减一,然后剩余n-1个数据再次构造为大根堆,再次交换,再次缩减,直至所有数据有序。建堆复杂度为O(n),调整堆复杂度为O(n logn)。最优的情况为所有叶节点铺满最底层,最差情况所有叶节点都没铺满,对复杂度的影响在常数级别,时间复杂度均为O(n logn)。

平均时间复杂度为O(n logn),空间复杂度为O(1),是一种不稳定的排序算法。

附算法实现源码:

//堆排序
template <class T>
void SiftDown(int left, int n, T Data[])
{int i = left;int j = 2*i + 1;T temp = Data[i];while(j < n){if((j < n - 1)&&(Data[j] < Data[j+1])) j++;if(temp < Data[j]){Data[i] = Data[j];i = j;j = 2*j + 1;}else break;}Data[i] = temp;
}template <class T>
void BuildHeap(int n, T Data[])
{for (int i = n/2-1; i >= 0; i--)SiftDown(i, n, Data);
}template <class T>
void Remove(T Data[], int n)
{SiftDown(0, n, Data);
}template <class T>
void HeapSort(T Data[], int n)
{BuildHeap(n, Data);for(int i = n-1; i > 0; i--){T t = Data[0];Data[0] = Data[i];Data[i] = t;Remove(Data, i);}
}

七、归并排序(Merge Sort)

归并排序采用分治法,基本思想为将已有序的子序列合并,得到完全有序的序列。以二路归并为例,首先将整个数据样本拆分为两个子样本, 并分别对它们进行排序,拆分后的两个子样本序列,再继续递归的拆分为更小的子数据样本序列, 再分别进行排序, 直到最后数据序列长度为1无法拆分,最后将同一级别下的子数据样本两两合并在一起,直到所有数据有序。归并排序的终极优化版本为TimSort,最好情况下可将时间复杂度降至O(n)。还有一种改进的原地归并算法可牺牲部分时间效率将空间复杂度降至O(1)

平均时间复杂度为O(n logn),空间复杂度为O(n),是一种稳定的排序算法。

附算法实现源码:

//归并排序
template <class T>
void Merge(T data[],int start,int mid,int end)
{int len1=mid-start+1;int len2=end-mid;int i,j,k;T* left=new T[len1];T* right=new T[len2];for(i=0;i<len1;i++){left[i]=data[i+mid+1];}for(i=0;i<len2;i++){right[i]=data[i+mid+1];}i=0,j=0;for(k=start;k<end;k++){if(i==len1||j==len2)break;if(left[i]<=right[j])data[k]=left[i++];elsedata[k]=right[j++];}while(i<len1){data[k++]=left[i++];}while(j<len2){data[k++]=left[j++];}delete[] left;delete[] right;
}template <class T>
void MergeSort(T data[],int start,int end)
{if(start<end){int mid=(start+end)/2;MergeSort(data,start,mid);MergeSort(data,mid+1,end);Merge(data,start,mid,end);}
}

八、基数排序(Radix Sort)

基数排序是一种基于非比较的整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个不同数位分别比较。原始基数排序的算法思想是将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零。然后从最低位开始依次进行一次排序。直到所有数据有序。基数排序时间复杂度为O(n×k),其中n为数据个数,k为数据位数。主要分为两种实现方法MSD(最高位优先)和LSD(最低位优先)。

平均时间复杂度为O(n×k),空间复杂度为O(n+k),是一种稳定的排序算法。

附算法实现源码:

//基数排序
const int RADIX=10;
template <class T>
struct LinkNode
{T data;LinkNode* next;
};template <class T>
struct TubNode
{LinkNode<T>* rear;LinkNode<T>* front;
};template <class T>
TubNode <T>* Distribute(T data[],int n,int ith)
{TubNode<T>* tube = new TubNode<T>[RADIX];memset(tube,0,sizeof(TubNode<T>)*RADIX);LinkNode<T>* t;for(int i=0;i<n;i++){T v=data[i];int j=ith-1;while(j--)v=v/RADIX;-v=v%RADIX;t=new LinkNode<T>;t->data=data[i];t->next=NULL;if(tube[v].front){tube[v].rear->next=t;tube[v].rear=t;}else{tube[v].front=tube[v].rear=t;}}return tube;
}template <class T>
void Collect(T data[],TubNode<T>*tube)
{LinkNode<T>*t,*p;int index=0;for(int i=0;i<RADIX;i++){p=t=tube[i].front;while(t){data[index++]=t->data;t=t->next;delete p;p=t;}}delete[] tube;
}template <class T>
void RadixSort(T data[],int n,int keys)
{TubNode<T>* tube;for(int i=0;i<keys;i++){tube=Distribute<T>(data,n,i+1);Collect<T>(data,tube);}
}

九、计数排序(Counting Sort)

计数排序是一种基于非比较的线性时间复杂度的排序方法,计数排序要求输入的数据必须是有确定范围K的整数。假定输入的元素是 n 个 0 到 k 之间的整数,它的运行时间是 Θ(n + k)。首先要找出待排序的数组中的最大元素和最小元素,然后统计数组中每个值为i的元素出现的次数存入数组Count[i],在之后对所有的计数进行累加(从数组Count第一个元素开始,每一项与前一项相加),最后反向填充目标数组(具体操作为:将每个元素i放在新数组的第Count[i]项,每放一个元素对应Count[i]减去一)。适用于对最大值不是很大的整型元素序列进行排序的情况。最好最坏复杂度都处在线性范围O(n+k)。

平均时间复杂度为O(n+k),空间复杂度为O(k),是一种稳定的排序算法。

附算法实现源码:

//计数排序
template <class T>
void CountingSort(T in_data[], T out_data[], int length,int k)
{T *temp = new T[k];for (int i = 0; i < k; i++){temp[i] = 0;}for (int i = 0; i < length; i++){temp[in_data[i]] += 1;}for (int i = 1; i < k; i++){temp[i] = temp[i] + temp[i - 1];}for (int i = length - 1; i >= 0; i--){out_data[temp[in_data[i]]-1] = in_data[i];temp[in_data[i]] -= 1;}delete[]temp;
}

十、桶排序(Bucket Sort)

桶排序属于计数排序的升级强化版,同时利用了分治的思想,将待排数据划分到一定数量的有序的桶里,然后再对每个桶中的数据进行排序(桶排序的稳定性取决于桶内排序算法是否稳定),最后再将各个桶里的数据有序的合并到一起。最理想的情况下,输入数据可以被均匀的分配在每一个桶中,时间复杂度可以降到O(n);最坏的情况为所有数据在同一个桶中进行排序,且使用了复杂度较高的排序算法,此时时间复杂度会变为O(n²)。为了使桶排序更加高效,需要做到以下两点:①在额外空间充足的情况下,尽量增加桶的数量。②使用的映射函数能够将输入的 N 个数据均匀的分配到 K 个桶中。

平均时间复杂度为O(n+k),空间复杂度为O(n+k),是一种稳定的排序算法。

附算法实现源码:

//桶排序
template <class T>
void Bucket_sort(T data[], int n, int max)
{T *buckets;if (data==NULL || n<1 || max<1){    return;}    if ((buckets=(T *)malloc(max*sizeof(T)))==NULL){return;}memset(buckets, 0, max*sizeof(T));for (int i = 0; i < n; i++){ buckets[data[i]]++; }for (int i = 0, j = 0; i < max; i++) {    while( (buckets[i]--) >0 ){    data[j++] = i;}}free(buckets);
}

相关代码后续会上传至网盘及个人资源,有需要者可自行下载。当然也可私信或留言博主私下获取!!!

链接:https://pan.baidu.com/s/1y9QuUpYLqzWxrQkD89tsSw 
提取码:6blj

参考目录:

首先感谢参考文献中各位大佬的整理、总结与分享。如果在文章中出现侵犯您的版权或隐私的行为,请私信或留言联系博主,博主会在第一时间进行回复并做出相应修改。再次感谢参考目录中出现的各位大佬,Thanks~~

排序:https://baike.baidu.com/item/%E6%8E%92%E5%BA%8F
冒泡排序:https://baike.baidu.com/item/%E5%86%92%E6%B3%A1%E6%8E%92%E5%BA%8F
插入排序:https://baike.baidu.com/item/%E6%8F%92%E5%85%A5%E6%8E%92%E5%BA%8F
选择排序:https://baike.baidu.com/item/%E9%80%89%E6%8B%A9%E6%8E%92%E5%BA%8F
快速排序:https://baike.baidu.com/item/%E5%BF%AB%E9%80%9F%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95
希尔排序:https://baike.baidu.com/item/%E5%B8%8C%E5%B0%94%E6%8E%92%E5%BA%8F
堆排序:https://baike.baidu.com/item/%E5%A0%86%E6%8E%92%E5%BA%8F
桶排序:https://baike.baidu.com/item/%E6%A1%B6%E6%8E%92%E5%BA%8F
计数排序:https://baike.baidu.com/item/%E8%AE%A1%E6%95%B0%E6%8E%92%E5%BA%8F
基数排序:https://baike.baidu.com/item/%E5%9F%BA%E6%95%B0%E6%8E%92%E5%BA%8F
归并排序:https://baike.baidu.com/item/%E5%BD%92%E5%B9%B6%E6%8E%92%E5%BA%8F
十大经典排序算法总结:https://jingyan.baidu.com/article/d3b74d64900eb05f77e609b7.html
上官致远_十大经典排序算法:https://zhuanlan.zhihu.com/p/41923298
blackboydec_排序算法时间复杂度、空间复杂度、稳定性比较:https://blog.csdn.net/yushiyi6453/article/details/76407640
排序算法时间复杂度以及空间复杂度:https://blog.csdn.net/liwei123liwei123/article/details/77868195
茶还是咖啡_八大排序总结:https://www.jianshu.com/p/8edba972b4b0
_code_x_十大常见排序算法的复杂度与代码实现:https://www.jianshu.com/p/4753b10a482c

十大常用经典排序算法总结!!!相关推荐

  1. 五种C语言非数值计算的常用经典排序算法

    摘要:排序是计算机的一种操作方法,其目的是将一组"无序"的记录序列调整为"有序"的记录序列,主要分为内部排序和外部排序. 排序 排序是计算机的一种操作方法,其目 ...

  2. 终于,把十大经典排序算法汇总了!(Java实现版)

    转载自  终于,把十大经典排序算法汇总了!(Java实现版) 最近几天在研究排序算法,看了很多博客,发现网上有的文章中对排序算法解释的并不是很透彻,而且有很多代码都是错误的,例如有的文章中在" ...

  3. 十大经典排序算法详细总结 图形展示 代码示例

    文章目录 十大经典排序算法详细总结 0.排序算法说明 1.冒泡排序(Bubble Sort) 2.选择排序(Selection Sort) 3.插入排序(Insertion Sort) 4.希尔排序( ...

  4. 十大经典排序算法及比较与分析 ( 动画演示 ) ( 可视化工具 )

    可视化工具及动画展示:旧金山大学 (usfca)|数据结构可视化工具 排序算法概念及描述:1.0 十大经典排序算法(文章部分内容引用自改文章) 参考:邓俊辉 的数据结构 本文未对排序算法概念进行详细说 ...

  5. 按复杂度有效性递减排序_十大经典排序算法:python源码实现,通俗深入讲解

    概述 提示:本文上万字,陆陆续续疏理知识点加测试代码,耗时近一个月.阅读时长40分钟左右. 本文将十大经典排序算法进行汇总,从源码实现.复杂度.稳定性进行分析,并对每种排序的特性进行点评.对典型算法, ...

  6. 算法 - 十大经典排序算法(动图演示)

    [TOC] 算法 - 十大经典排序算法(动图演示) ​ 在计算机科学与数学中,一个排序算法(英语:Sorting algorithm)是一种能将一串资料依照特定排序方式进行排列的一种算法.最常用到的排 ...

  7. 算法设计与分析——十大经典排序算法二(6--10)

    一个不知名大学生,江湖人称菜狗 original author: jacky Li Email : 3435673055@qq.com  Time of completion:2023.3.1 Las ...

  8. 一文搞定十大经典排序算法

    更多内容关注公众号:SAP Technical 一.排序算法概述 1.定义 将杂乱无章的数据元素,通过一定的方法按关键字顺序排列的过程叫做排序. 2.分类 十种常见排序算法可以分为两大类: 非线性时间 ...

  9. 十大经典排序算法动画与解析,看我就够了

    作者 | 程序员小吴 转载自五分钟学算法(ID: CXYxiaowu) 排序算法是<数据结构与算法>中最基本的算法之一. 排序算法可以分为内部排序和外部排序.内部排序是数据记录在内存中进行 ...

  10. 十大经典排序算法(建议收藏)

    来自:Damonare的个人博客 原文:http://blog.damonare.cn/2016/12/20/十大经典排序算法总结(javascript描述)/ 0.算法概述  0.1 算法分类 十种 ...

最新文章

  1. 第三十期:BAT 为什么都看上了重庆?
  2. 2021年中国手机游戏行业研究报告
  3. 【算法分析与设计】数组循环移位问题
  4. TM4C123核心板焊接须知
  5. CPU多核并发缓存架构介绍
  6. 基于Netty的RPC简易实现
  7. Linux 桌面进化史
  8. 【语音隐藏】基于matlab LSB语音信息隐藏【含Matlab源码 577期】
  9. python存数据到impala_0039-如何使用Python Impyla客户端连接Hive和Impala
  10. TextWatcher实现输入关键字筛选数据
  11. 关于睡眠分期中人工判读的一些个人总结
  12. 《高效能人士的七个习惯》:运用才是关键
  13. python中import与input_Python import与from import使用及区别介绍
  14. python画线段代码_python画线代码
  15. vue和 element ui下载到本地后引入
  16. Pinyin4j---JAVA拼音解决方案
  17. 解决BMap is not defined?
  18. 巧记作宾语补足语的省略to 的动词不定式
  19. 中国历届亚运会成绩排名(金牌数)
  20. 记录一篇Spring 5的WebClient 的 重试问题

热门文章

  1. Ribbon 界面介绍(1)
  2. 世界上有多少数据?应该如何保护?
  3. Python Selenium IE 上传文件和 处理网页对话框showModalDailog模态对话框
  4. 什么叫服务器加密狗信息异常,客户很多反应,服务器安装了CA认证,如果咱们的加密狗是黄色的,就会提示演示版,重新注册也不行。...
  5. 阿里代码检查p3c插件使用
  6. 福州大学计算机科学与技术 何x玲,吴伶 - 福州大学 - 数学与计算机科学学院
  7. echarts柱状图参数详解
  8. Ubuntu虚拟机中无法使用罗技鼠标滚轮功能
  9. postman安装报错 无法定位_接口测试工具postman安装及使用
  10. android videoview截屏,android VideoView截屏黑屏解决方法