【以下所有示例均以从小到大排序为例】
(一)插入排序
1.直接插入排序
【基本思想】将数列分成有序区和无序区,从无序区中选取一个数与有序区的数依次比较后插入合适的位置,该位置后的有序区记录依次后移,直到全部记录排好序。时间复杂度O(n^2)
↓←←←←←←←←←←←←←←←←↑
R1 ≤ R2 ≤ R3 ≤······≤ Ri-1 | Ri , Ri+1 , Ri+2 ,······ , Rn
有序区 无序区
原始数列: [51] 33 62 17 28 51'
第一趟: [33 51] 62 17 28 51'
第二趟: [33 51 62] 17 28 51'
第三趟: [17 33 51 62] 28 51'
第四趟: [17 28 33 51 62] 51'
第五趟: [17 28 33 51 51' 62]
2.折半插入排序
【基本思想】在直接插入排序的基础上改进,由于前半部分已经是有序数列,在查找插入位置时使用高效率的“折半查找”。
该方法仅减少关键字的比较次数,却没有减少记录的移动次数,时间复杂度仍为O(n^2)
3.二路插入排序
【基本思想】另开一个循环数组d[],将第一个关键字R0赋值给d[1],将大于R0的数插入R0之后的有序数组,将小于R0的数插入R0之前的有序数组。需附加n个记录的辅助空间
原始数列: [51] 33 62 17 28 51'
第一次: [51]
第二次: [51] [33]
第三次: [51 62] [33]
第四次: [51 62] [17 33]
第五次: [51 62] [17 28 33]
第六次: [51 51' 62] [17 28 33]
first指针指向17,final指针指向62
4.希尔排序(又称缩小增量法)
【基本思想】设置增量d1(<n),将全部n个记录分成d1组,把所有相隔d1的记录放在一个组中,即[k],[k+d],[k+2d]...在一组,在组内进行直接插入排序,依次取每组第i个记录得到的序列为一趟希尔排序的结果;设置新的增量d2<d1,重复分组排序,直到增量di减少到1。【跳跃式分堆儿排序】
【注】增量序列取法:①没有除1之外的公因子;②增量递减,最后一个增量值必须为1。
原始数列:49 38 65 97 76 13 27 49' 55 04
d=5 分组:[49 13] [38 27] [65 49'] [97 55] [76 04]
组内排序:[13 49] [27 38] [49' 65] [55 97] [04 76]
第一趟希尔排序结果:13 27 49’ 55 04 49 38 65 97 76
d=3 分组:[ 13 55 38 76] [ 27 04 65 ] [ 49' 49 97]
第二趟希尔排序的结果:13 04 49' 38 27 49 55 65 97 76
d=1 ,共一大组,组内排序
第三趟希尔排序的结果:04 13 27 38 49’49 55 65 76 97
(二)交换排序
1.冒泡排序
【基本思想】给定一组数列,相邻两数相比较,逆序则交换。【两两比较,小者上浮,大者下沉】
最多经过n-1次冒泡可将n个数据全部排序
最好情况,初始序列有序,比较n-1次,移动0
最坏情况,初始序列倒序,比较n(n-1)/2,移动3n(n-1)/2
原始数列: [51] 33 62 17 28 51'
51>33,交换;51<62,不变;62>17,交换;62>28,交换;62>51',交换
第一趟冒泡排序结果:33 51 17 28 51’ 62
依次类推
2.快速排序
【基本思想】选取一个基数(每组第一个数),大于基数的在一堆儿,小于基数的再另一堆儿,等于基数的和大于的分一堆儿;在每一个堆儿里继续选取基数重复分堆儿直到不能再分(堆儿里只有一个记录)
最好情况,每次划分得到的子序列长度大致相等,C(n)≤O(n*lbn).
最坏情况,每次划分得到一个(n-1)的堆儿和一个空堆儿,即初始数列有序,
快排平均时间复杂度O(nlbn),最差为O(n^2);平均空间复杂度S(n)=O(lbn);
原始数列:[51] 33 62 17 28 51'
第一趟后:[28 33 17 ] 51 [ 51' 62] //??28在第一个??
第二趟后:[17] 28 [33] 51 51' [62]
结束
(三)选择排序
1.简单选择排序
【基本思想】分为有序区和无序区,从无序区选取最小的一个记录放在有序区的最小位置(两个记录交换),重复。
这个有点像直接插入排序,不同的是简单选择排序是依次在无序区的记录中比较,而直接插入排序是在有序区中比较。
最好情况,移动次数0
最差情况,移动次数3(n-1)
平均时间复杂度O(n^2)
原始数列:51 33 62 17 28 51'
第一趟:[17] 33 62 51 28 51’ (51和17交换位置)
第二趟:[17 28] 62 51 33 51'
第三趟:[17 28 33] 51 62 51'
第四趟:[17 28 33 51] 62 51'
第五趟:[17 28 33 51 51'] 62
第六趟:[17 28 33 51 51' 62]
2.树形选择排序
【基本思想】首先对n个记录的关键字进行两两比较,选取n/2个较小者;然后这n/2个较小者进行两两比较....如此重复,知道只剩1个关键字为止。
每选择一个记录需要将进行[lbn]次比较,时间复杂度为O(nlbn)
缺点:需要较多的辅助空间,与最大值进行多次多余的比较
原始数列:51 33 62 17 28 51'
一趟树形选择排序过程:(从下往上依次两两比较,选取较小的记录,直至选择出最小的一个)
17
17 28
33 17 28
51 33 62 17 28 51’
3.堆排序
【堆的性质】
1.堆是一棵采用顺序存储结构的完全二叉树
2.堆的根节点是关键字序列中的最小(或最大)值,分别称为小(或大)根堆
3.从根节点到每一个叶子节点路径上的元素组成的序列都是按照元素值非递减(非递增)的
4.堆中的任意子树也是堆
(四)归并排序
【基本思想】将数列分成n个组,每个组一个元素(即每个组都是有序的),两组之间两两合并,组内排序使之有序,重复至只有一个组。【有点像快排反着来的,en也不是很确切】
具有n个待排记录的归并次数为lbn,一趟归并的时间复杂度为O(n),整个归并(无论最好最坏情况)时间复杂度为O(nlbn),空间复杂度O(n)。
原始数列:[51] [33] [62] [17] [28] [51']
一趟归并:[33 51] [17 62] [28 51']
两趟归并:[17 33 51 62 ] [28 51']
三趟归并:[17 28 33 51 51' 62]
(五)基数排序(不需要进行关键字比较和记录移动)
1.多关键字排序
2.链式基数排序
排序方法 | 平均时间复杂度 | 最坏情况 | 辅助空间 | 稳定性 |
直接插入排序 | O(n^2) | O(n^2) | O(1) | 稳定 |
冒泡排序 | O(n^2) | O(n^2) | O(1) | 稳定 |
直接选择排序 | O(n^2) | O(n^2) | O(1) | 稳定 |
希尔排序 | O(n^1.3) | O(n^1.3) | O(1) | 不稳定 |
快速排序 | O(nlbn) | O(n^2) | O(lbn) | 不稳定 |
堆排序 | O(nlbn) | O(nlbn) | O(1) | 不稳定 |
归并排序 | O(nlbn) | O(nlbn) | O(n) | 稳定 |
基数排序 | O(d*(rd+n)) | O(d*(rd+n)) | O(rd) | 稳定 |