各类排序算法

这篇博客详细介绍了几种常见的排序算法,包括插入排序、树排序、堆排序、归并排序、快速排序、冒泡排序、选择排序和基数排序。每种排序算法的步骤、基本思想和注意事项都得到了阐述,对于理解各种排序算法的原理及其应用非常有帮助。

1. 插入排序

 

 

插入排序的基本操作就是将一个数据插入到已经排好序的有序数据中 , 从而得到一个新的,个数加一的有序数据,算法适用于少量数据的排序, 时间复杂度为 O(n^2) . 是稳定的排序方法。插入算法把要排序的数组分成两部分:第一部分包含了这个数组的所有元素,但将最后一个元素除外,而第二部分就只包含这一个元素。在第一部分排序后,再把这个最后元素插入到此刻已是有序的第一部分里的位置

 

算法步骤  

 

     1. 从有序数列和无序数列 {a2,a3, ,an} 开始进行排序;

 

   2. 处理第 i 个元素时 (i=2,3, ,n) , 数列 {a1,a2, ,ai-1} 是已有序的 , 而数列 {ai,ai+1, ,an} 是无序的。用 ai ai-1 a i-2, ,a1 进行比较 , 找出合适的位置将 ai 插入;

 

   3. 重复第二步,共进行 n-1 次插入处理,数列全部有序。

 

基本思想

 

     每次处理就是将无序数列的第一个元素与有序数列的元素从后往前逐个进行比较,找出插入位置,将该元素插入到有序数列的合适位置中。

 

 

注意事项

 

     在容器已经有序时将获得最好的时间性能 (O(n)), 容器近似有序时也将获得很好的时间性能

 

 

2. 树排序  

 

 

  算法步骤      

 

       1. 首先执行查找算法,找出被插结点的父亲结点。

 

   2. 判断被插结点是其父亲结点的左、右儿子。将被插结点作为叶子结点插入。

 

   3. 若二叉树为空。则首先单独生成根结点。

 

  注意:新插入的结点总是叶子结点。

 

  基本思想

 

      插入之后,直接构造成红黑树。第 i 项的插入最多需要 log2i 次迭代。如需要重构,则之多需要 (log2i)/2 次迭代

 

 

   注意事项

 

   1. 树排序是快速而稳定的,但空间需求与 n 成线性关系

 

   2. 如果即将插入的一项 y 等于红黑树中已经存在的一项 x ,那么 y 将被插入到 x 的右子树中

 

 

 

3. 堆排序

 

 

 

  算法步骤   

 

      1. 初始化操作:将 R[1..n] 构造为初始堆;

 

    2. 每一趟排序的基本操作:将当前无序区的堆顶记录 R[1] 和该区间的最后一个记录交换,然后将新的无序区调整为堆 ( 亦称重建堆 )  

 

  

  基本思想

 

    以大根堆为例 ( 大根堆和小根堆:根结点 ( 亦称为堆顶 ) 的关键字是堆里所有结点关键字中最小者的堆称为小根堆,又称最小堆。

 

                         根结点 ( 亦称为堆顶 ) 的关键字是堆里所有结点关键字中最大者,称为大根堆,又称最大堆 )

 

        1. 先将初始文件 R[1..n] 建成一个大根堆 , 此堆为初始的无序区

 

   2. 再将关键字最大的记录 R[1]( 即堆顶 ) 和无序区的最后一个记录 R[n] 交换,由此得到新的无序区 R[1..n-1] 和有序区 R[n] ,且满足 R[1..n-1].keys R[n].key

 

   3. 由于交换后新的根 R[1] 可能违反堆性质,故应将当前无序区 R[1..n-1] 调整为堆。然后再次将 R[1..n-1] 中关键字最大的记录 R[1] 和该区间的最后一个记录 R[n-1] 交换,由此得到新的无序区 R[1..n-2] 和有序区 R[n-1..n] ,且仍满足关系 R[1..n- 2].keys R[n-1..n].keys ,同样要将 R[1..n-2] 调整为堆。

 

  ……

 

  直到无序区只有一个元素为止。

 

 

 

   注意事项

 

      1. 只需做 n-1 趟排序,选出较大的 n-1 个关键字即可以使得文件递增有序。

 

   2. 用小根堆排序与利用大根堆类似,只不过其排序结果是递减有序的。堆排序和直接选择相反:在任何时刻堆排序中无序区总是在有序区之前,且有序区是在原向量的尾部由后往前逐步扩大至整个向量为止

 

      3. 堆排序的时间,主要由建立初始堆和反复重建堆这两部分的时间开销构成,它们均是通过调用 Heapify 实现的。 堆排序的最坏时间复杂度为 O(nlog2n) 。堆序的平均性能较接近于最坏性能。 由于建初始堆所需的比较次数较多,所以堆排序不适宜于记录数较少的文件。

 

  堆排序是就地排序,辅助空间为 O(1)

 

  它是不稳定 的排序方法。

 

 

    堆排序与直接选择排序的区别

 

  直接选择排序中,为了从 R[1..n] 中选出关键字最小的记录,必须进行 n-1 次比较,然后在 R[2..n] 中选出关键字最小的记录,又需要做 n-2 次比较事实上,后面的 n-2   比较中,有许多比较可能在前面的 n-1 次比较中已经做过,但由于前一趟排序时未保留这些比较结果,所以后一趟排序时又重复执行了这些比较操作。

 

  堆排序可通过树形结构保存部分比较结果,可减少比较次数。

 

 

4. 归并排序

 

 

       算法步骤      

 

         1. 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列

 

   2. 设定两个指针,最初位置分别为两个已经排序序列的起始位置

 

   3. 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置

 

   4. 重复步骤 3 直到某一指针达到序列尾

 

   5. 将另一序列剩下的所有元素直接复制到合并序列尾

 

 

    基本思想

 

        归并排序是建立在归并操作上的一种有效的排序 算法。该算法是采用分治法 Divide and Conquer )的一个非常典型的应用。

 

   将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表。

 

    注意事项

 

      1. 时间 O(nlogn)

 

     2. 空间 O(n)

 

   3. 与快速排序类似。

 

      4. 归并排序是稳定的排序 . 即相等的元素的顺序不会改变

 

 

5. 快速排序

 

 

      算法步骤

 

     1 设置两个变量 I J ,排序开始的时候: I=0 J=N-1

 

   2 以第一个数组元素作为关键数据,赋值给 key ,即 key=A[0]

 

   3 J 开始向前搜索,即由后开始向前搜索( J=J-1 ),找到第一个小于 key 的值 A[J] ,并与 A[I] 交换;

 

   4 I 开始向后搜索,即由前开始向后搜索( I=I+1 ),找到第一个大于 key A[I] ,与 A[J] 交换;

 

   5 重复第 3 4 5 步,直到 I=J (3,4 步是在程序中没找到时候 j=j-1 i=i+1 ,直至找到为止。找到并交换的时候 i j 指针位置不变。另外当 i=j 这过程一定正好是 i+ j+ 完成的最后另循环结束 )

 

 

基本思想

 

 

设要排序的数组是 A[0] …… A[N-1] ,首先任意选取一个数据(通常选用第一个数据,但从效率上讲最好选枢轴, 枢轴指 first first+ (last-first)/2,last-1 中最小的那一项)作为关键数据, 然后将所有比它小的数都放到它前面,所有比它大的数都放到它后面,这个过程称为一趟快速排序

 

  注意事项

 

 

1. 如果原来的数组时按照顺序或者逆序排列的,则快速算法的效率是最高的。如果每次迭代中,枢轴是最小项或者最大项时,将出现最坏的情况。

 

2. 快速排序是不稳定的

 

3.worstSpace(n) n 成线性关系

 

4. 快速排序在平均情况下非常快,而在最坏情况下则很慢,它是不稳定的,并且也不是本地排序方法

 

5. 快速排序吸引人之处在于平均情况下的快速性

 

 

6. 冒泡法排序

 

 

算法步骤

 

 

基本思想

 

依次比较相邻的两个数,将小数放在前面,大数放在后面。即在第一趟:首先比较第 1 个和第 2 个数,将小数放前,大数放后。然后比较第 2 个数和第 3 个数,将小数放前,大数放后,如此继续,直至比较最后两个数,将小数放前,大数放后。至此第一趟结束,将最大的数放到了最后。在第二趟:仍从第一对数开始比较(因为可能由于第 2 个数和第 3 个数的交换,使得第 1 个数不再小于第 2 个数),将小数放前,大数放后,一直比较到倒数第二个数(倒数第一的位置上已经是最大的),第二趟结束,在倒数第二的位置上得到一个新的最大数(其实在整个数列中是第二大的数)。如此下去,重复以上过程,直至最终完成排序。

 

 

注意事项

 

 

时间复杂度为 O(n^2)

 

执行的总比较次数为 n*(n-1)/2

 

 

 

7. 选择法排序

 

 

 

算法步骤

 

基本思想

 

 

      1. 初始状态:无序区为 R[1..n] ,有序区为空。

 

   2. 1 趟排序

 

  在无序区 R[1..n] 中选出关键字最小的记录 R[k] ,将它与无序区的第 1 个记录 R[1] 交换,

 

      使 R[1..1] R[2..n] 分别变为记录个数增加 1 个的新有序区和记录个数减少 1    新无序区。 .....

 

   3. i 趟排序

 

  第 i 趟排序开始时,当前有序区和无序区分别为 R[1..i-1] R(1 i n-1) 。该趟排序从当前无序区中选出关键字最小的记录 R[k] ,将它与无序区的第 1 个记录 R 交换,

 

      使 R [1..i] R 分别变为记录个数增加 1 个的新有序区和记录个数减少 1 个的新无序区。

 

 

注意事项

 

 

1.n 个记录的文件的直接选择排序可经过 n-1 趟直接选择排序得到有序结果

 

2. 时间复杂度为 O(n^2)

 

3. 共执行比较的次数为 n(n-1)/2

 

 

8. 基数排序

 

 

 

1. LSD 的基数排序适用于位数小的数列,如果位数多的话,使用 MSD 的效率会比较好,

 

MSD 的方式恰与 LSD 相反,是由高位数为基底开始进行分配,其他的演算方式则都相同。

 

 

2. 时间效率:设待排序列为 n 个记录, d 个关键码,关键码的取值范围为 radix ,则进行链式基数排序的时间复杂度为 O(d(n+radix)) ,其中,一趟分配时间复杂度为 O(n)

 

    一趟收集时间复杂度为 O(n) ,共进行 d 趟分配和收集。

 

    空间效率:需要 2*radix 个指向队列的辅助空间,以及用于静态链表的 n 个指针

 

 

3. 在某些时候,基数排序法的效率高于其它的比较性排序法。

 

 

算法步骤

 

 

首先根据个位数的数值,在走访数值时将它们分配至编号 0 9 的桶子中:

 

      0

 

   1 81

 

   2 22

 

   3 73 93 43

 

   4 14

 

   5 55 65

 

   6

 

   7

 

   8 28

 

   9 39

 

     接下来将这些桶子中的数值重新串接起来,成为以下的数列:

 

   81, 22, 73, 93, 43, 14, 55, 65, 28, 39

 

  接着再进行一次分配,这次是根据十位数来分配:

 

   0

 

   1 14

 

   2 22 28

 

   3 39

 

   4 43

 

   5 55

 

   6 65

 

   7 73

 

   8 81

 

   9 93

 

  接下来将这些桶子中的数值重新串接起来,成为以下的数列:

 

   14, 22, 28, 39, 43, 55, 65, 73, 81, 93

 

      这时候整个数列已经排序完毕;如果排序的对象有三位数以上,则持续进行以上的动作直至最高位数为止。

 

 

基本思想

 

 

基数排序的方式可以采用 LSD Least significant digital )或 MSD Most significant digital ), LSD 的排序方式由键值的最右边开始,而 MSD 则相反,由键值的最左边开始。

 

 

注意事项

 

 

73, 22, 93, 43, 55, 14, 28, 65, 39, 81

 

 

每一趟从待排序的数据元素中选出最小(或最大)的一个元素,顺序放在已排好序的数列的最后,直到全部待排序的数据元素排完。

 

  选择排序是不稳定的排序方法。

 

设想被排序的数组 R 1..N ]垂直竖立,将每个数据元素看作有重量的气泡,根据轻气泡不能在重气泡之下的原则,从下往上扫描数组 R ,凡扫描到违反本原则的轻气泡,就使其向上 " 漂浮 " ,如此反复进行,直至最后任何两个气泡都是轻者在上,重者在下为止

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值