十大常用经典排序算法总结!!!

十大常用经典排序算法总结!!!爆肝整理 堪称全网最详细的十大常用经典排序算法总结 写在开头 本文经过参考多方资料整理而成 全部参考目录会附在文章末尾 很多略有争议性的细节都是在不断查阅相关资料后总结的 具有一定普适性 总表 相关解释 稳定 如果原本序列中 a 在 b 前面且 a b 排序后 a 仍在 b 前面 顺序不变 不稳定 如果原本序列中 a 在 b 前面且 a b 排序后 a 可能在 b 后面 顺序可能发生改变 内排序 所有排序操作均在内存中完成 外排序 由于数据量太大 将其放入磁盘中 排序过程中需要磁盘与内存之间的数据传输

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

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

总表:

十大常用经典排序算法总结!!!

相关解释:

稳定:如果原本序列中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)

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 
  
    void BubbleSort(T data[],int n) { int flag=0; for(int i=0;i 
    
  

二、快速排序(Quick Sort)

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

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

附算法实现源码:

//快速排序 template 
  
    int Partition(T data[],int left,int right) { T pivot=data[left]; while(left 
   
     pivot) right--; data[left]=data[right]; while(left 
    
      void QuickSort(T data[],int left,int right) { if(left 
      
     
    
  

三、选择排序(Selection Sort)

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

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

附算法实现源码:

 //选择排序 template 
  
    void SelectionSort(T data[],int n) { for(int i=1;i 
    
  

四、插入排序(Insertion Sort)

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

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

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

//直接插入排序 template 
  
    void InsertionSort(T Data[],int n) { int p,i; for(p=1;p 
   
     =0&&Data[i]>temp) { Data[i+1]=Data[i]; i--; } Data[i+1]=temp; } } //折半插入排序 template 
    
      void BinaryInsertionSort(T Data[],int n) { int left,mid,right,p; for(p=1;p 
     
       temp) right=mid-1; else left=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 
  
    void ShellSort(T Data[],int n) { int d=n/2; while(d>=1) { for(int k=0;k 
   
     =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 
  
    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 
   
     void BuildHeap(int n, T Data[]) { for (int i = n/2-1; i >= 0; i--) SiftDown(i, n, Data); } template 
    
      void Remove(T Data[], int n) { SiftDown(0, n, Data); } template 
     
       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 
  
    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 
   
     void MergeSort(T data[],int start,int end) { if(start 
     
    
  

八、基数排序(Radix Sort)

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

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

附算法实现源码:

//基数排序 const int RADIX=10; template 
  
    struct LinkNode { T data; LinkNode* next; }; template 
   
     struct TubNode { LinkNode 
    
      * rear; LinkNode 
     
       * front; }; template 
      
        TubNode 
       
         * Distribute(T data[],int n,int ith) { TubNode 
        
          * tube = new TubNode 
         
           [RADIX]; memset(tube,0,sizeof(TubNode 
          
            )*RADIX); LinkNode 
           
             * t; for(int i=0;i 
            
              ; 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 
             
               void Collect(T data[],TubNode 
              
                *tube) { LinkNode 
               
                 *t,*p; int index=0; for(int i=0;i 
                
                  data; t=t->next; delete p; p=t; } } delete[] tube; } template 
                 
                   void RadixSort(T data[],int n,int keys) { TubNode 
                  
                    * tube; for(int i=0;i 
                   
                     (data,n,i+1); Collect 
                    
                      (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 
  
    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 
  
    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://javaforall.net/223356.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月17日 下午2:16
下一篇 2026年3月17日 下午2:16


相关推荐

  • JetBrick 入门详解

    JetBrick 入门详解JetBrick的简单使用方法,仅作为简单的入门,不做内部详细的探讨。

    2022年6月17日
    37
  • 如何获取select下拉框选中的的值呢

    如何获取select下拉框选中的的值呢select 元素 下拉列表 select 元素用于创建下拉列表 而 option 元素用于定义列表中待选择的选项 列表通常会把首个选项显示为被选选项 提示 select 元素是一种表单控件 可用于在表单中接受用户输入 属性 autofocus 下拉列表在页面加载时自动获得焦点 是一个布尔属性 disabled select option select select

    2026年3月17日
    2
  • 二维vector初始化的几种方法

    二维vector初始化的几种方法FillConstruc defineM4 defineN4 onestep recommendeds vector std vector int gt matrix M std vector int N 0 twostepsstd vector int row N 0 std vector std vector int gt matrix2 M ro std vector int int int std vector int

    2026年3月17日
    2
  • ldapsearch 参数表

    ldapsearch 参数表下表描述可以用于 ldapsearch 的区分大小写的参数 参数用途 打印关于使用 ldapsearch 的帮助 aderef 指定别名反向引用 请输入 never always search 或 find 如果不使用此参数 缺省为 never A 只检索属性的名称 而不检索属性的值 bbasedn

    2026年3月19日
    2
  • HTC One(M8)正式发布,实现 Lytro 光场相机的袖珍化

    HTC One(M8)正式发布,实现 Lytro 光场相机的袖珍化014 3 26 00 04 nbsp nbsp 何宗丞伦敦 纽约 HTC 董事长王雪红和 CEO 周永明分别在大洋彼岸的两个城市 揭开了 HTC 新一代旗舰 HTCOne M8 尽管这款机器的谍照早已在网上一览无遗 但作为一款关乎 HTC 复兴的关键机型 外界仍对它寄予了较高的关注度 HTCOne M8 延续了上一代产品的设计 在金属用料上更为纯粹 采用金属拉丝的一体化机身

    2026年3月17日
    4
  • opc服务器消息通知代码,OPC 服务器 操作示例源码

    opc服务器消息通知代码,OPC 服务器 操作示例源码【实例简介】TestOPC【实例截图】【核心代码】usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;usingHaiGrang.Package.OpcNetApiChs.DaNet;usingHaiGrang.Package.OpcNetApiChs.Opc;usingHaiGr…

    2022年6月20日
    30

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号