分治法与归并排序

首先来决一个基本的问题:如何合并两个有序序列?
同样,我们也采取图形演示的方法,来一步一步解决问题,假设我们现在存在两个有序序列: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];

    }
  • 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

现在我们来总结一下:两个有序队列可以很容易的合并成一个有序队列,合并的效率也是比较高的,可以达到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];

    }


}

--------------------- 本文来自 江湖人称小白哥 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/dd864140130/article/details/50859687?utm_source=copy

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值