02.Merge Sort 归并排序

Merge Sort 归并排序

算法复杂度为:O(NlogN)

算法思想:先一分为二递归到底,回溯的时候两部分就已排好了序,再将这两部分合并。

1.基础版

import java.util.Arrays;
public class MergeSort {
    public static void sort(int[] arr) {
        // 包含边界的排序,并归排序!

        sort(arr, 0, arr.length - 1);
    }

    private static void sort(int[] arr, int left, int right){

        // 递归终止条件
        if(left >= right)
            return;

        // 分界点
        int middle = (right - left) / 2 + left;

        // 递入
        sort(arr, left, middle);
        sort(arr, middle + 1, right);

        // 并归
        merge(arr, left, middle, right);
    }

    private static void merge(int[] arr, int left, int middle, int right) {
        int[] temp = new int[right - left + 1];

        int l = 0; // 左边:向左偏移left
        int r = middle + 1 - left; // 右边:向左偏移left

        // 将需要排序的部分复制到temp数组中
        for (int i = left; i <= right; i++) {
            temp[i - left] = arr[i];
        }

        // @@@判断并赋值到arr数组中@@@
        int i = left;
        while(i <= right) {

            // 如果左边的都已经排完了,
            // 那么右边剩下的一定是有序并且
            // 与在源数组的最右边
            if(l > middle - left) // 有偏移
                break;

            // 如果右边的排完了,那么只需要排左边的
            if(r > right - left) { // 有偏移
                arr[i++] = temp[l];
                l ++;
                continue;
                // 如果走到这一步,下面的就不能进行判断了,
                // 因为r的值已经越界,如果继续执行下面的
                // 判断语句,会发生索引越界报错。
            }

            // 谁小我就把谁放进源数组中,同时相关的索引自增。
            if(temp[l] < temp[r]) {
                arr[i++] = temp[l];
                l ++;
            } else {
                arr[i++] = temp[r];
                r ++;
            }
        }
    }

    public static void main(String[] args) {

        int[] arr = {0, 1, 0, 4, 3, 7, 1, 0, 0, 9, 0};
        sort(arr);
        System.out.println(Arrays.toString(arr));
    }
}

2.优化综合版(其实没有很大的作用)

import java.util.Random;

public class MergeSortPlus {
    public static void sort(int[] arr) {
        // 包含边界的排序,并归排序,综合优化版!

        sort(arr, 0, arr.length - 1);
    }

    private static void sort(int[] arr, int left, int right){

        // @@@ 优化点1 @@@
        // 当递归到一定阶段的时候,
        // 采用直接插入排序方式进行排序。
        if(right - left < 15) {
            insertionSort(arr, left, right);
            return;
        }

        // 分界点
        int middle = (right - left) / 2 + left;

        // 递入
        sort(arr, left, middle);
        sort(arr, middle + 1, right);

        // 并归
        // @@@ 优化点2 @@@,
        // 如果当前已经有序,则不需要递归
        if(arr[middle] > arr[middle + 1])
            merge(arr, left, middle, right);
    }

    private static void merge(int[] arr, int left, int middle, int right) {
        int[] temp = new int[right - left + 1];

        int l = 0;
        int r = middle + 1 - left;

        for (int i = left; i <= right; i++) {
            temp[i - left] = arr[i];
        }

        int i = left;
        while(i <= right) {

            if(l > middle - left) // 有偏移
                break;

            if(r > right - left) { // 有偏移
                arr[i++] = temp[l];
                l ++;
                continue;
            }

            if(temp[l] < temp[r]) {
                arr[i++] = temp[l];
                l ++;
            } else {
                arr[i++] = temp[r];
                r ++;
            }
        }
    }

    private static void insertionSort(int[] arr, int left, int right) {

        for (int i = left; i <= right; i++) {
            int e = arr[i];
            int j = i;
            for( ; j > left && arr[j-1] - e > 0 ; j--)
                arr[j] = arr[j-1];
            arr[j] = e;
        }
    }

    public static void main(String[] args) {

        int n = 10000000;
        Random random = new Random();
        int[] arr = new int[n];
        for (int i = 0; i < n; i++) {
            arr[i] = random.nextInt(Integer.MAX_VALUE);
        }
        long start = System.currentTimeMillis();
        sort(arr);
        long end = System.currentTimeMillis();

        for (int i = 1; i < arr.length; i++) {
            if(arr[i - 1] > arr[i]) {
                System.out.println(arr[i - 1] + " " + arr[i]);
                throw new IllegalArgumentException("排序失败");
            }

        }
        System.out.println("用时:" + (end - start) / 1000.0 + "s");
    }
}

你可能感兴趣的:(02.Merge Sort 归并排序)