排序算法
排序是将无需的记录序列调整为有序记录序列的一种操作。
包括:冒泡排序,选择排序,堆排序,插入排序,希儿排序,快速排序,归并排序等。
(一)
冒泡排序
- 基本思想:
每次进行相邻两个元素的比较,如果为逆序时即进行交换,直到没有反序的数据元素为止。
- 排序过程:
设想被排序的数组R[1..N]垂直竖立,将每个数据元素看作有重量的气泡,根据轻气泡不能在重气泡之下的原则,从下往上扫描数组R,凡扫描到违反本原则的轻气泡,就使其向上"漂浮",如此反复进行,直至最后任何两个气泡都是轻者在上,重者在下为止。
- 示例:对36 23 87 16 11
进行冒泡排序的过程:
初始时:36
23 87 16 11
第一趟:23
36 16 11 87
第二趟:23
16 11 36 87
第三趟:16
11 23 36 87
第四趟:11
16 23 36 87
代码如下所示
1. /** 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. |
(二)
选择排序
- 基本思想:
每一趟在n-i+1(i=1,2,3,...,n-1)个记录中选取关键字最小的记录作为有序序列中的第i个记录。
- 排序过程:
- 将整个记录序列划分为有序区域和无序区域,有序区域位于最左端,无序区域位于右端,初始状态有序区域为空,无序区域含有待排序的所有n个记录。
- 设置一个整型变量index,用于记录在一趟的比较过程中,当前关键字值最小的记录位置。开始将它设定为当前无序区域的第一个位置,即假设这个位置的关键字最小,然后用它与无序区域中其他记录进行比较,若发现有比它的关键字还小的记录,就将index改为这个新的最小记录位置,随后再用a[index].key
与后面的记录进行比较,并根据比较结果,随时修改index的值,一趟结束后index中保留的就是本趟选择的关键字最小的记录位置。 - 将index位置的记录交换到无序区域的第一个位置,使得有序区域扩展了一个记录,而无序区域减少了一个记录。
- 不断重复 (2)、(3),直到无序区域剩下一个记录为止。此时所有的记录已经按关键字从小到大的顺序排列就位。
- 示例:对36 23 87 16 11
进行选择排序的过程:
初始时:36
23 87 16 11
第一趟:11
[36 23 87 16]
第二趟:11
16 [36 23 87]
第三趟:11
16 23 [36 87]
第四趟:11
16 23 36 [87]
结
果
:11
16 23 36 87
代码如下所示
1. /** 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. |
(三)
堆排序
- 基本思想:
将堆看成是一棵以k1为根的完全二叉树,则这棵完全二叉树中的每个非终端结点的值均不大于(或不小于)其左、右孩子结点的值。由此可以看出,若一棵完全二叉树是堆,则根结点一定是这n个结点中的最小者或最大者。
- 堆的定义
N个元素的序列K1,K2,K3,...,Kn.称为堆,当且仅当该序列满足特性:
Ki≤K2i
Ki ≤K2i+1(1≤
I≤ [N/2]) - 排序过程:
首先将待排序的记录序列构造一个堆,此时,选出了堆中所有记录的最小者或最大者,然后将它从堆中移走,并将剩余的记录再调整成堆,这样又找出了次小(或次大)的记录,以此类推,直到堆中只有一个记录为止,每个记录出堆的顺序就是一个有序序列。
代码如下所示
1. /** 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71. 72. 73. 74. 75. 76. 77. 78. 79. 80. 81. 82. 83. 84. 85. 86. 87. 88. 89. 90. 91. 92. 93. 94. 95. 96. 97. |
(四)
插入排序
- 基本思想:
每次将一个待排序的数据元素,插入到前面已经排好序的数列中的适当位置,使数列依然有序;直到待排序数据元素全部插入完为止。
- 排序过程:
将待排序表看做是左、右两部分,其中左边为有序区,右边为无序区,整个排序过程就是将右边无序区中的记录依次按关键字大小逐个插入到左边有序区中,以构成新的有序区,直到全部记录都排好序。
- 示例:对36
23 87 16 11
进行插入排序的过程:初始:36 23 87 16 11
一趟:23 36
87 16 11二趟:23 36
87 16 11三趟:16 23 36 87
11四趟:11 16 23 36 87
代码如下所示
1. /** 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. |
(五)
希儿排序
- 基本思想:
希儿排序又称为缩小增量排序,是将待排序的记录划分成几组,从而减少参与直接插入排序的数据量,当经过几次分组排序后,记录的排列已经基本有序,这个时候再对所有的记录实施直接插入排序。
- 排序过程:
假设带排序的记录为n个,先取整数step
< n作为步长,通常选取step = n / 2 (n / 2表示不大于n
/ 2的最大整数),将所有距离为step的记录构成一组,从而将整个待排序记录序列分割称为step个子序列。反复比较相距step的两数,当两个数不等时,将小的交换到前面,直到所有相距step的两数符合从小到大的顺序,倍减步长,重复上面分组,直到步长为1,即将所有记录放在一组进行一次直接插入排序,最终将所有记录重新排列成按关键字有序的序列。 - 示例:对4 1 10 2 16 9 3 14进行希儿排序的过程:
- 因为关键字有8个,第一次步长step
= 8 / 2 = 4初始:4
1
10 2
16
9
3 14一趟:4
1
3 2
16
9
10 14
(只有10,3这一组不符合,按升序排列) - 第二次步长step = 4 / 2 = 2
初始:4
1 3 2
16 9
10 14
二趟:3
1 4 2
10 9
16 14
(2组都按升序排列)
- 第三次步长step = 2 / 2 = 1
初始:3 1 4 2 10 9 16 14
三趟:1 2 3 4 9 10 14 16
(按升序排列)
代码如下所示
1. /** 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. |
(六)
快速排序
- 基本思想:
通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
θ(n)。
- 排序过程:
设要排序的数组是A[0]……A[N-1]。
- 设置两个变量i、j,排序开始的时候:i=0,j=N-1;
- 以第一个数组元素作为关键数据,赋值给key,即key=A[0];
- 从j开始向前搜索,即由后开始向前搜索(j--),找到第一个小于key的值A[j],将A[j]和A[i]互换;
- 从i开始向后搜索,即由前开始向后搜索(i++),找到第一个大于key的A[i],将A[i]和A[j]互换;
- 重复第3、4步,直到i=j;
(3,4步中,没找到符合条件的值,即3中A[j]不小于key,4中A[i]不大于key的时候改变j、i的值,使得j=j-1,i=i+1,直至找到为止。找到符合条件的值,进行交换的时候i,
j指针位置不变。另外,i==j这一过程一定正好是i+或j-完成的时候,此时令循环结束)。
- 示例:对36 23 87 16 11
进行快速排序的过程:初始:36 23 87 16 11
(i = 0, j = 4, key = 36)一趟:11
23 87 16 11 (i = 0, j = 4, j位置覆盖i位置)二趟:11 23 87 16
87 (i = 2, j = 4, i++, i位置是比key大,i覆盖j位置)三趟:11
23 1616 87
(i = 2, j = 3, j--, j位置比key小,j覆盖i位置)四趟:11 23 16
3687 (i = 3, j = 3, i++, i == j, key覆盖i位置)递归:左边 11 23 16
右边 87
代码如下所示
1. /** 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71. |
(七)
归并排序
- 基本思想:
归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide
and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。 - 排序过程:
比较a[i]和a[j]的大小,若a[i]≤a[j],则将第一个有序表中的元素a[i]复制到r[k]中,并令i和k分别加上1;否则将第二个有序表中的元素a[j]复制到r[k]中,并令j和k分别加上1,如此循环下去,直到其中一个有序表取完,然后再将另一个有序表中剩余的元素复制到r中从下标k到下标t的单元。归并排序的算法我们通常用递归实现,先把待排序区间[s,t]以中点二分,接着把左边子区间排序,再把右边子区间排序,最后把左区间和右区间用一次归并操作合并成有序的区间[s,t]。
- 示例:对4 1 10 2 16 9 3 14
进行插入归并的过程:初始:4 1 10 2 16 9 3 14
一趟:[1, 4], [2, 10], [9, 16], [3, 14]
二趟:[1, 2, 4, 10], [3, 9, 14, 16]
三趟:[1, 2, 3, 4, 9, 10, 14, 16]
代码如下所示
1. /** 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. |
运行实例比较
排序法 |
平均时间 |
最差情形 |
稳定度 |
额外空间 |
备注 |
冒泡 |
O(n2) |
O(n2) |
稳定 |
O(1) |
n小时较好 |
选择 |
O(n2) |
O(n2) |
不稳定 |
O(1) |
n小时较好 |
堆 |
O(nlogn) |
O(nlogn) |
不稳定 |
O(1) |
n大时较好 |
插入 |
O(n2) |
O(n2) |
稳定 |
O(1) |
大部分已排序时较好 |
希尔 |
O(nlogn) |
O(ns) 1<s<2 |
不稳定 |
O(1) |
s是所选分组 |
快速 |
O(nlogn) |
O(n2) |
不稳定 |
O(nlogn) |
n大时较好 |
归并 |
O(nlogn) |
O(nlogn) |
稳定 |
O(1) |
n大时较好 |
参考:
- http://wenku.baidu.com/view/bddf836cbe23482fb4da4c38.html
- http://wenku.baidu.com/view/6382f3bfc77da26925c5b043.html
- http://wenku.baidu.com/view/4c2890abdd3383c4bb4cd255.html
- http://wenku.baidu.com/view/56306f0303d8ce2f006623bf.html
- http://wenku.baidu.com/view/192e6f0e763231126edb11e3.html
- http://wenku.baidu.com/view/4a0c4718f12d2af90342e60c.html
- http://baike.baidu.com/link?url=ahN1k6xgm0rpMiS7KDHxNWLobbiH7WLBgB92qShxsycCH_S4LY8bC-RKoU1MHCc7MIAYNqwD1NndnCgeAdnXRq