zoukankan      html  css  js  c++  java
  • 归并排序 递归and非递归

    什么是归并排序

    • 归并排序其实就做两件事: 
      1. “分解”——将序列每次折半划分。
      2. “合并”——将划分后的序列段两两合并后排序。
     

    首先我们来看一下分解是怎样实现的呢?

     
    1. // 递归退出条件,及left》=right的时候
    2. if (left < right) {
    3. // 找出中间索引
    4. center = (left + right) / 2;
    5. // 对左边数组进行递归
    6. mSort(k, 0, center);
    7. // 对右边数组进行递归
    8. mSort(k, center + 1, right);
    9. // 合并
    10. merging(k, left, center, right);
    11. }
     

    接着合并是怎样实现的呢?

    1. 初始化一个数组,将左右数组的数进行比较,将较小的数存入中间数组
    2. 再将左右数组剩下的数存到中间数组
    3. 最后,将中间数组复制回原来的数组
     
    1. private static void merging(int[] k, int left, int center, int right) {
    2. int tempArr[] = new int[k.length];// 存放数据的数组
    3. // third记录中间数组的索引
    4. int mid = center + 1;
    5. int third = left;
    6. int temp = left;
    7. while (left <= center && mid <= right) {
    8. // 从左右两个数组找出最小的数存入tempArr数组
    9. if (k[left] < k[mid]) {
    10. tempArr[third++] = k[left++];
    11. } else {
    12. tempArr[third++] = k[mid++];
    13. }
    14. }
    15. // 剩余部分依次放入中间数组
    16. while (mid <= right) {
    17. tempArr[third++] = k[mid++];
    18. }
    19. while (left <= center) {
    20. tempArr[third++] = k[left++];
    21. }
    22. // 将中间数组中的内容复制回原数组
    23. while (temp <= right) {
    24. k[temp] = tempArr[temp++];
    25. }
    26. }
    27. }
     

    递归版 的源码实现如下

     
    1. //下面是递归版的
    2. package com.xujun.mergesort;
    3. public class MergeSort {
    4. static int[] a = new int[] { 20, 9, 3, 5, 26, 100, 8, -1, 7, 50, -5 };
    5. public static void main(String[] args) {
    6. System.out.println("before sort");
    7. ArrayUtils.printArray(a);
    8. mergeSort(a);
    9. System.out.println("after sort");
    10. ArrayUtils.printArray(a);
    11. }
    12. private static void mergeSort(int[] k) {
    13. mSort(k, 0, k.length - 1);
    14. }
    15. private static void mSort(int[] k, int left, int right) {
    16. int center
    17. // 递归退出条件,及left》=right的时候
    18. if (left < right) {
    19. // 找出中间索引
    20. center = (left + right) / 2;
    21. // 对左边数组进行递归
    22. mSort(k, 0, center);
    23. // 对右边数组进行递归
    24. mSort(k, center + 1, right);
    25. // 合并
    26. merging(k, left, center, right);
    27. }
    28. }
    29. private static void merging(int[] k, int left, int center, int right) {
    30. // 存放数据的数组
    31. int tempArr[] = new int[k.length];
    32. // third记录中间数组的索引
    33. int mid = center + 1;
    34. int third = left;
    35. int temp = left;
    36. while (left <= center && mid <= right) {
    37. // 从左右两个数组找出最小的数存入tempArr数组
    38. if (k[left] < k[mid]) {
    39. tempArr[third++] = k[left++];
    40. } else {
    41. tempArr[third++] = k[mid++];
    42. }
    43. }
    44. // 剩余部分依次放入中间数组
    45. while (mid <= right) {
    46. tempArr[third++] = k[mid++];
    47. }
    48. while (left <= center) {
    49. tempArr[third++] = k[left++];
    50. }
    51. // 将中间数组中的内容复制回原数组
    52. while (temp <= right) {
    53. k[temp] = tempArr[temp++];
    54. }
    55. }
    56. }
     

    下面说一下分递归版的实现思路

    1. 从归并段的长度为1开始,一次使归并段的长度变为原来的2倍。
    2. 在每趟归并的过程中,要注意处理归并段的长度为奇数和 最后一个归并段的长度和前面的不等的情况,需要做一下处理
     
    1. // 程序边界的处理非常重要
    2. while (len <= t.length) {
    3. for (int i = 0; i + len <= t.length - 1; i += len * 2) {
    4. // System.out.println("len="+len);
    5. low = i;
    6. mid = i + len - 1;
    7. high = i + len * 2 - 1;
    8. if (high > t.length - 1)
    9. high = t.length - 1;
    10. merge(t, i, mid, high);
    11. }
    12. //长度加倍
    13. len += len;
    14. }
    15. return true;
    16. }

    源码如下:

     
      1. package com.xujun.mergesort1;
      2. public class MergeSort2 {
      3. /**
      4. * 二路归并排序的递归算法-入口
      5. *
      6. * @param <T>
      7. * @param t
      8. * @return
      9. */
      10. public static <T extends Comparable> boolean mergeSortRecursive(T[] t) {
      11. if (t == null || t.length <= 1)
      12. return true;
      13. MSortRecursive(t, 0, t.length - 1);
      14. return true;
      15. }
      16. /**
      17. * 二路归并排序的递归算法-递归主体
      18. *
      19. * @param <T>
      20. * @param t
      21. * @param low
      22. * @param high
      23. * @return
      24. */
      25. private static <T extends Comparable> boolean MSortRecursive(T[] t,
      26. int low, int high) {
      27. if (t == null || t.length <= 1 || low == high)
      28. return true;
      29. int mid = (low + high) / 2;
      30. MSortRecursive(t, low, mid);
      31. MSortRecursive(t, mid + 1, high);
      32. merge(t, low, mid, high);
      33. return true;
      34. }
      35. public static <T extends Comparable> boolean mergeSortNonRecursive(T[] t) {
      36. if (t == null || t.length <= 1)
      37. return true;
      38. int len = 1;
      39. int low = 0;
      40. int mid;
      41. int high;
      42. // 程序边界的处理非常重要
      43. while (len <= t.length) {
      44. for (int i = 0; i + len <= t.length - 1; i += len * 2) {
      45. // System.out.println("len="+len);
      46. low = i;
      47. mid = i + len - 1;
      48. high = i + len * 2 - 1;
      49. if (high > t.length - 1)
      50. high = t.length - 1;
      51. merge(t, i, mid, high);
      52. }
      53. //长度加倍
      54. len += len;
      55. }
      56. return true;
      57. }
      58. /**
      59. * 将两个归并段合并成一个归并段
      60. *
      61. * @param <T>
      62. * @param t
      63. * @param low
      64. * @param mid
      65. * @param high
      66. * @return
      67. */
      68. private static <T extends Comparable> boolean merge(T[] t, int low,
      69. int mid, int high) {
      70. T[] s = t.clone();// 先复制一个辅助数组
      71. int i, j, k;// 三个指示器,i指示t[low...mid],j指示t[mid+1...high],k指示s[low...high]
      72. for (i = low, j = mid + 1, k = low; i <= mid && j <= high; k++) {
      73. if (t[i].compareTo(t[j]) <= 0) {
      74. s[k] = t[i++];
      75. } else {
      76. s[k] = t[j++];
      77. }
      78. }
      79. // 将剩下的元素复制到s中
      80. if (i <= mid) {
      81. for (; k <= high; k++) {
      82. s[k] = t[i++];
      83. }
      84. } else {
      85. for (; k <= high; k++) {
      86. s[k] = s[j++];
      87. }
      88. }
      89. for (int m = low; m <= high; m++) {// 将辅助数组中的排序好的元素复制回原数组
      90. t[m] = s[m];
      91. }
      92. return true;
      93. }
      94. public static void main(String[] args) {
      95. Integer[] arr = new Integer[] { 2, 3, 6, 8, 9, 2, 0, 1 };
      96. long startTime = System.currentTimeMillis(); // 获取开始时间
      97. mergeSortRecursive(arr);
      98. long endTime = System.currentTimeMillis(); // 获取开始时间
      99. System.out.println("执行时间:" + (endTime - startTime));
      100. for (int i : arr) {
      101. System.out.println(i);
      102. }
      103. startTime = System.currentTimeMillis(); // 获取开始时间
      104. mergeSortNonRecursive(arr);
      105. endTime = System.currentTimeMillis(); // 获取开始时间
      106. System.out.println("执行时间:" + (endTime - startTime));
      107. for (int i : arr) {
      108. System.out.println(i);
      109. }
      110. }
      111. }
    哔哔叭哔哄
  • 相关阅读:
    HDU 1010 Tempter of the Bone(DFS剪枝)
    HDU 1013 Digital Roots(九余数定理)
    HDU 2680 Choose the best route(反向建图最短路)
    HDU 1596 find the safest road(最短路)
    HDU 2072 单词数
    HDU 3790 最短路径问题 (dijkstra)
    HDU 1018 Big Number
    HDU 1042 N!
    NYOJ 117 求逆序数 (树状数组)
    20.QT文本文件读写
  • 原文地址:https://www.cnblogs.com/he-px/p/7489464.html
Copyright © 2011-2022 走看看