数据结构--冒泡排序、归并排序、快速排序、选择排序、插入排序(Java版)

深藏阁楼爱情的钟 2022-05-26 12:13 271阅读 0赞

一、冒泡排序

1、思路

  • 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
  • 针对所有的元素重复以上的步骤,直到没有任何一对元素需要比较。

2、实现

  1. /** * 排序算法的接口 * @author hoaven */
  2. public interface ISort {
  3. /** * 对数组array进行升序排序 * @param array */
  4. public void sort(int[] array);
  5. }
  6. /** * 冒泡排序 * 时间复杂度: 平均情况与最差情况都是O(n^2) * 空间复杂度: O(1) * * @author hoaven * @see ISort */
  7. public class BubbleSort implements ISort {
  8. public void sort(int[] array) {
  9. int temp = 0;
  10. for (int i = 0; i < array.length - 1; i++) {
  11. for (int j = i + 1; j < array.length; j++) {
  12. if (array[i] > array[j]) {
  13. temp = array[i];
  14. array[i] = array[j];
  15. array[j] = temp;
  16. }
  17. }
  18. }
  19. }
  20. }

二、归并排序

1、思路

  • 初始状态:无序区为R[1..n],有序区为空。
  • 第1趟排序: 在无序区R[1..n]中选出关键字最小的记录R[k],将它与无序区的第1个记录R[1] 交换,使R[1..1]和R[2..n]分别变为记录个数增加1个的新有序区和记录个数减少1个的新无序区。
  • 第i趟排序: 第i趟排序开始时,当前有序区和无序区分别为R[1..i-1]和R[i..n](1≤i≤n-1)。 该趟排序从当前无序区中选出关键字最小的记录R[k],将它与无序区的第1个记录R[i]交换,使R[1..i] 和R[i+1..n]分别变为记录个数增加1个的新有序区和记录个数减少1个的新无序区。

2、实现

  1. /** * 归并排序<br> * 时间复杂度: 平均情况与最差情况都是O(nlog(n))<br> * 空间复杂度: It Depends * @author hoaven * @see ISort */
  2. public class MergeSort implements ISort {
  3. public void sort(int[] array) {
  4. int[] auxArray = new int[array.length];
  5. mergeSort(array, auxArray, 0, array.length - 1);
  6. }
  7. /** * 基于分治思想,执行归并排序 * @param low 待排序数组下标下界 * @param high 待排序数组下标上界 */
  8. private void mergeSort(int[] array, int[] auxArray, int low, int high) {
  9. int dividedIndex = 0; // 分治位置索引变量
  10. if (low < high) {
  11. dividedIndex = (low + high) / 2; // 计算分治位置(采用简单的二分思想)
  12. mergeSort(array, auxArray, low, dividedIndex); // 左侧递归归并排序
  13. mergeSort(array, auxArray, dividedIndex + 1, high); // 右侧递归归并排序
  14. merge(array, auxArray, low, dividedIndex, high); // 合并分治结果
  15. }
  16. }
  17. private void merge(int[] array, int[] auxArray, int low, int dividedIndex, int high) {
  18. int i = low; // 指向左半分区数组的指针
  19. int j = dividedIndex + 1; // 指向右半分区数组的指针
  20. int auxPtr = 0; // 指向辅助区数组的指针
  21. // 合并两个有序数组:array[low..dividedIndex]与array[dividedIndex+1..high]。
  22. while (i <= dividedIndex && j <= high) { // 将两个有序的数组合并,排序到辅助数组auxArray中
  23. if (array[i] > array[j]) { // 左侧数组array[low..dividedIndex]中的array[i]大于右侧数组array[dividedIndex+1..high]中的array[j]
  24. auxArray[auxPtr++] = array[j++];
  25. } else {
  26. auxArray[auxPtr++] = array[i++];
  27. }
  28. }
  29. // 如果array[low..dividedIndex].length>array[dividedIndex+1..high].length,经过上面合并
  30. // array[low..dividedIndex]没有合并完,则直接将array[low..dividedIndex]中没有合并的元素复制到辅助数组auxArray中去
  31. while (i <= dividedIndex) {
  32. auxArray[auxPtr++] = array[i++];
  33. }
  34. // 如果array[low..dividedIndex].length<array[dividedIndex+1..high].length,经过上面合并
  35. // array[dividedIndex+1..high]没有合并完,则直接将array[dividedIndex+1..high]中没有合并的元素复制到辅助数组auxArray中去
  36. while (j <= high) {
  37. auxArray[auxPtr++] = array[j++];
  38. }
  39. // 最后把辅助数组auxArray的元素复制到原来的数组中去,归并排序结束
  40. for (auxPtr = 0, i = low; i <= high; i++, auxPtr++) {
  41. array[i] = auxArray[auxPtr];
  42. }
  43. }
  44. }
  45. //假设待排序数组为array = {94,12,34,76,26,9,0,37,55,76,37,5,68,83,90,37,12,65,76,49},数组大小为20,我们以该数组为例,执行归并排序的具体过程:
  46. [94,12,34,76,26,9,0,37,55,76, 37,5,68,83,90,37,12,65,76,49]
  47. [94,12,34,76,26, 9,0,37,55,76]
  48. [94,12,34, 76,26]
  49. [94,12, 34]
  50. [94, 12]
  51. {
  52. 12, 94}
  53. {
  54. 12,34, 94}
  55. [76, 26]
  56. {
  57. 26, 76}
  58. {
  59. 12,26,34, 76,94}
  60. [9,0,37, 55,76]
  61. [9,0, 37]
  62. [9, 0]
  63. {
  64. 0, 9}
  65. {
  66. 0,9, 37}
  67. [55, 76]
  68. {
  69. 55, 76}
  70. {
  71. 0,9,37, 55,76}
  72. {
  73. 0,9,12,26,34, 37,55,76,76,94}
  74. [37,5,68,83,90, 37,12,65,76,49]
  75. [37,5,68, 83,90]
  76. [37,5, 68]
  77. [37, 5]
  78. {
  79. 5, 37}
  80. {
  81. 5,37, 68}
  82. [83, 90]
  83. {
  84. 83, 90}
  85. {
  86. 5,37,68, 83,90}
  87. [37,12,65, 76,49]
  88. [37,12, 65]
  89. [37, 12 ]
  90. {
  91. 12, 37 }
  92. {
  93. 12,37, 65 }
  94. [76, 49 ]
  95. {
  96. 49, 76}
  97. {
  98. 12,37,49, 65,76}
  99. {
  100. 5,12,37,37,49, 65,68,76,83,90}
  101. {
  102. 0,5,9,12,12,26,34,37,37,37, 49,55,65,68,76,76,76,83,90,94}
  103. //上面示例的排序过程中,方括号表示“分解”操作过程中,将原始数组进行递归分解,直到不能再继续分割为止;
  104. //花括号表示“归并”的过程,将上一步分解后的数组进行归并排序。
  105. //因为采用递归分治的策略,所以从上面的排序过程可以看到,“分解”和“归并”交叉出现。

三、快速排序

1、思路

  • 在R[low..high]中任选一个记录作为基准Pivot;
  • 使左边子区间中所有记录的关键字均小于等于基准;
  • 右边的子区间中所有记录的关键字均大于等于基准;

2、实现

  1. /** * 快速排序<br> * 时间复杂度: 平均情况是O(nlog(n)),最差情况是O(n^2)<br> * 空间复杂度: O(nlog(n)) * @author hoaven * @see ISort */
  2. public class QuickSort implements ISort {
  3. public void sort(int[] array) {
  4. quickSort(array, 0, array.length - 1);
  5. }
  6. /** * 通过划分,基于分治思想,递归执行子任务排序最后合并 * @param low 数组首位置索引 * @param high 数组末位置索引 */
  7. private void quickSort(int[] array, int low, int high) {
  8. int pivotPos; // 划分基准元素索引
  9. if (low < high) {
  10. pivotPos = partition(array, low, high);
  11. quickSort(array, low, pivotPos - 1); // 左划分递归快速排序
  12. quickSort(array, pivotPos + 1, high); // 右划分递归快速排序
  13. }
  14. }
  15. /** * 简单划分方法:排列数组array左边的都小于它,右边的都大于它 * @param i * @param j * @return */
  16. private int partition(int[] array, int i, int j) {
  17. Integer pivot = array[i]; // 初始基准元素,如果quickSort方法第一次调用,pivot初始为数组第一个元素
  18. while (i < j) { // 两个指针从两边向中间靠拢,不能相交
  19. // 右侧指针向左移动
  20. while (j > i && array[j] >= pivot) {
  21. j--;
  22. }
  23. if (i < j) { // 如果在没有使指针i和j相交的情况下找到了array[j] >= 基准元素pivot
  24. array[i] = array[j]; // 基准元素放到了j指针处
  25. i++; // 左侧i指针需要向右移动一个位置
  26. }
  27. // 左侧指针向右移动
  28. while (i < j && array[i] <= pivot) {
  29. i++;
  30. }
  31. if (i < j) { // 如果在没有使指针i和j相交的情况下找到了array[i] <= 基准元素pivot
  32. array[j] = array[i]; // 基准元素放到了i指针处
  33. j--; // 右侧j指针需要向左移动一个位置
  34. }
  35. }
  36. array[i] = pivot; // 将基准元素放到正确的排序位置上
  37. return i;
  38. }
  39. }

四、选择排序

1、思路

每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。

2、实现

  1. /** * 选择排序<br> * 时间复杂度: 平均情况与最差情况都是O(n^2)<br> * 空间复杂度: O(1) * @author hoaven * @see ISort */
  2. public class SelectionSort implements ISort {
  3. public void sort(int[] array) {
  4. int temp = 0;
  5. for(int i = 0; i < array.length; i++){
  6. temp = array[i];
  7. for(int j = i; j < array.length; j++){
  8. if(temp > array[j]){
  9. temp = array[j];
  10. }
  11. }
  12. if(temp != array[i]){
  13. array[i] = temp;
  14. }
  15. }
  16. }
  17. }

五、插入排序

1、思路

要求在一个已排好序的数据序列中插入一个数,但要求插入后此数据序列仍然有序。

2、实现

  1. /** * 插入排序实现 * @author hoaven * */
  2. public class InsertSort implements ISort {
  3. public void sort(int[] array) {
  4. for(int i = 1; i < array.length; i++){
  5. int temp = array[i];
  6. int j = i - 1;
  7. while(j >= 0 && array[j] > temp){
  8. array[j + 1] = array[j];
  9. j--;
  10. }
  11. if(j != i - 1){
  12. array[j + 1] = temp;
  13. }
  14. }
  15. }
  16. }

发表评论

表情:
评论列表 (有 0 条评论,271人围观)

还没有评论,来说两句吧...

相关阅读