经典排序算法系列4-归并排序

2019-11-22  本文已影响0人  xgangzai

Merging Sort - 归并排序

需求

对N个整数升序排序

思路

把数组分成两部分(递归均分,直至每部分只有一个元素),每部分先排序,然后合并有序的两部分。利用到了分治思想,一般来讲,分治思想需要递归编程来实现。

算法评判

实现代码如下

public void sort(int[] arr) {
    int[] result = new int[arr.length];
    mergeRecursive(arr, result, 0, arr.length - 1);
}

//递归
private void mergeRecursive(int[] arr, int[] result, int start, int end) {
    if (start >= end) {
        return;
    }

    //对半分
    int len = end - start;
    int middle = len >> 1;
    int start1 = start;
    int end1 = start1 + middle;
    int start2 = end1 + 1;
    mergeRecursive(arr, result, start1, end1);
    mergeRecursive(arr, result, start2, end);

    //合并两个组到result中
    int k = start;
    while (start1 <= end1 && start2 <= end) {
        if (arr[start2] < arr[start1]) {
            result[k++] = arr[start2++];
        } else {
          //如果后部分不小于前部分,可能的情况是两个元素相等,优先取前部分的
            result[k++] = arr[start1++];
        }
    }

    //拷贝剩余的
    if (start1 <= end1) {
        System.arraycopy(arr, start1, result, k, end1 + 1 - start1);
    }
    if (start2 <= end) {
        System.arraycopy(arr, start2, result, k, end + 1 - start2);
    }

    //将合并好的拷贝到原数组中
    System.arraycopy(result, start, arr, start, end + 1 - start);

}

关于稳定性,因为在合并两个有序数组时,当两个元素相等,优先取前部分中的元素,所以归并排序是稳定的。

这种思路是从上而下,还有一种自下而上的思路,从每个子序只有一个元素开始,每两两合并,直至最终合并成一个序列,代码实现如下

private void sortMerge(int[] arr) {
    int[] orderedArr = new int[arr.length];
    //i 每组数量
    for (int i = 2; i < arr.length * 2; i *= 2) {
        //j 组数
        for (int j = 0; j < (arr.length + i - 1) / i; j++) {
            int left = i * j;
            //mid 是右半部分的第一个元素下标
            int mid = left + i / 2 >= arr.length ? (arr.length - 1) : (left + i / 2);
            int right = i * (j + 1) - 1 >= arr.length ? (arr.length - 1) : (i * (j + 1) - 1);
            int start = 0, l = left, m = mid;
            //因为mid是右半部分的第一个元素下标,所以等号在右半部分
            while (l < mid && m <= right) {
                if (arr[m] < arr[l]) {
                    orderedArr[start++] = arr[m++];
                } else {
                  //如果相等,优先取前部分的元素,保证稳定性
                    orderedArr[start++] = arr[l++];
                }
            }
            while (l < mid) {
                orderedArr[start++] = arr[l++];
            }
            while (m <= right) {
                orderedArr[start++] = arr[m++];
            }
            System.arraycopy(orderedArr, 0, arr, left, right - left + 1);

        }
    }
}

问题:时间复杂度计算

上一篇下一篇

猜你喜欢

热点阅读