老生常谈——分治法与归并排序

来源:互联网 发布:mac air app 编辑:程序博客网 时间:2024/06/06 00:52

首先来决一个基本的问题:如何合并两个有序序列?
同样,我们也采取图形演示的方法,来一步一步解决问题,假设我们现在存在两个有序序列:1,3,5和2,4,6,7.
那么我们首先应该在脑海中画出这样的一副图形:
这里写图片描述

到现在,我们已经有解决问题的思路了:

比较这两个序列的第一个元素,谁较小就输出谁,,然后将较小的元素从原队列删除.如此往下进行,如果某个队列为空,则直接将另一个队列中元素依序输出就好.

按照上面的思路,整个过程用图形演示:
1. 选取较小元素
这里写图片描述
2. 选取较小元素
这里写图片描述
3. 选取较小元素
这里写图片描述
4. 选取较小元素
这里写图片描述
5. 选取较小元素,此时队列arr1已经为空了,因此后面只需要依次输出arr2中的元素即可
这里写图片描述
6. 输出元素
这里写图片描述
7. 输出元素
这里写图片描述

到现在整个过程已经描述清楚了.在具体的代码实现过程中,删除操作可以用移动下标来实现(许多操作,其实换个角度来想的)
代码实现为:

 public static void merge(int[] arr, int start, int mid, int end, int[] temp) {        int m = mid;        int n = end;        int i = start;        int j = mid + 1;        int z = 0;        while (i <= m && j <= n) {            if (arr[i] < arr[j]) {                temp[z++] = arr[i++];            } else {                temp[z++] = arr[j++];            }        }        while (i <= m) {            temp[z++] = arr[i++];        }        while (j <= n) {            temp[z++] = arr[j++];        }        for (i = 0; i < z; i++)            arr[start + i] = temp[i];    }

现在我们来总结一下:两个有序队列可以很容易的合并成一个有序队列,合并的效率也是比较高的,可以达到O(n).
反向思考一下,任何一个序列(n>1)都可以被拆分成两个子序列,如果这两个子序列是有序的,那么可以很容易的将这两个子序列合并成有序序列。

ok,现在我们来回忆一下分治法:

把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题……直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并。

结合我们刚才思考的,我们可以设想:任何一个序列(n>1),都可以不断的被一分为二,直到最后的序列中只有一个元素,只有一个元素的序列当然是有序的。

现在我们已经有一种排序的新思路了:为了让原始序列arr有序,可将它分成A,B两个序列,为让A,B两个序列有序,可以继续将A序列拆成A1,A2两个序列,如此拆分下去,直到序列中只有一个元素。对于B序列也是同样的操作。拆分完毕之后,再合并相近的两个序列就行。
恭喜你,一步一步找到一种排序的新思路——归并排序。现在我们要做的就是通过递归分解数列,然后通过合并就可以完成归并排序了。
实现代码如下:

public class MergeSort {    public static void main(String[] args) {        int[] arr3 = {1, 2, 5, 4};        int[] temp = new int[arr3.length];        sort(arr3, 0, arr3.length - 1, temp);        for (int i = 0; i < temp.length; i++) {            System.out.print(temp[i] + " ");        }    }    public static void sort(int[] arr1, int start, int end, int[] temp) {        if (start < end) {            int mid = (start + end) / 2;            System.out.println("mid " + mid + "    " + start + ">" + mid + "---" + (mid + 1) + ">" + end);            sort(arr1, start, mid, temp);            sort(arr1, mid + 1, end, temp);            merge(arr1, start, mid, end, temp);        }    }    public static void merge(int[] arr, int start, int mid, int end, int[] temp) {        int m = mid;        int n = end;        int i = start;        int j = mid + 1;        int z = 0;        while (i <= m && j <= n) {            if (arr[i] < arr[j]) {                temp[z++] = arr[i++];            } else {                temp[z++] = arr[j++];            }        }        while (i <= m) {            temp[z++] = arr[i++];        }        while (j <= n) {            temp[z++] = arr[j++];        }        for (i = 0; i < z; i++)            arr[start + i] = temp[i];    }}
0 0
原创粉丝点击