1. 程式人生 > >歸並排序及優化(Java實現)

歸並排序及優化(Java實現)

繼續 soft local == else 歸並排序 right 數據 cal

普通歸並排序

public class MergeSort {
    /**
     * @param arr   待排序的數組
     * @param left  本次歸並的左邊界
     * @param mid   本次歸並的中間位置,也就是分界線
     * @param right 本次歸並的右邊界
     * @param <T>   泛型
     * @local aux   輔助空間(Auxiliary Space)
     */
    private static <T extends Comparable<? super T>> void merge(T[] arr, int left, int mid, int right) {
        T[] aux = java.util.Arrays.copyOfRange(arr, left, right + 1);

        //aux,i j分別是這兩半的起始指針。將這兩個閉區間歸並[left ... mid]   [mid + 1 ... right]
        int i = left;
        int j = mid + 1;

        for (int t = left; t <= right; t++) {//把arr數組中的[left...right]區間都覆蓋了,就完事了
            if (i > mid) { //i == mid + 1 時越界(躍出左半數組)
                arr[t] = aux[j++ - left];
            } else if (j > right) {//j == right + 1 時越界(躍出右半數組)
                arr[t] = aux[i++ - left];
            } else if (aux[i - left].compareTo(aux[j - left]) < 0) {//如果i-left小,那麽插入。(左半邊數組的指針所指的數小)
                arr[t] = aux[i++ - left];
            } else { //如果j-left小,那麽插入。(右半邊數組的指針所指的數小)
                arr[t] = aux[j++ - left];
            }
        }
    }

    private static <T extends Comparable<? super T>> void sort(T[] arr, int left, int right) {
        if (left >= right) {
            return;
        }

        int mid = (left + right) / 2;
        sort(arr, left, mid);
        sort(arr, mid + 1, right);
        merge(arr, left, mid, right);
    }

    public static <T extends Comparable<? super T>> void sort(T[] arr) {
        sort(arr, 0, arr.length - 1);
    }

    private static void printArr(Object[] arr) {
        for (Object o : arr) {
            System.out.print(o);
            System.out.print("\t");
        }
        System.out.println();
    }

    public static void main(String args[]) {
        Integer[] arr = {3, 5, 1, 7, 2, 9, 8, 0, 4, 6};
        printArr(arr);//3   5   1   7   2   9   8   0   4   6
        sort(arr);
        printArr(arr);//0   1   2   3   4   5   6   7   8   9
    }
}

  

歸並優化:利用插入排序

當遞歸到規模足夠小時,利用插入排序

public class MergeSort {
    /**
     * @param arr   待排序的數組
     * @param left  本次歸並的左邊界
     * @param mid   本次歸並的中間位置,也就是分界線
     * @param right 本次歸並的右邊界
     * @param <T>   泛型
     * @local aux   輔助空間(Auxiliary Space)
     */
    private static <T extends Comparable<? super T>> void merge(T[] arr, int left, int mid, int right) {
        T[] aux = java.util.Arrays.copyOfRange(arr, left, right + 1);

        //aux,i j分別是這兩半的起始指針。將這兩個閉區間歸並[left ... mid]   [mid + 1 ... right]
        int i = left;
        int j = mid + 1;

        for (int t = left; t <= right; t++) {//把arr數組中的[left...right]區間都覆蓋了,就完事了
            if (i > mid) { //i == mid + 1 時越界(躍出左半數組)
                arr[t] = aux[j++ - left];
            } else if (j > right) {//j == right + 1 時越界(躍出右半數組)
                arr[t] = aux[i++ - left];
            } else if (aux[i - left].compareTo(aux[j - left]) < 0) {//如果i-left小,那麽插入。(左半邊數組的指針所指的數小)
                arr[t] = aux[i++ - left];
            } else { //如果j-left小,那麽插入。(右半邊數組的指針所指的數小)
                arr[t] = aux[j++ - left];
            }
        }
    }

    /**
     * @param arr   當規模小的時候對arr采用插入排序
     * @param left  待排序部分的左邊界
     * @param right 待排序部分的右邊界
     * @param <T>   泛型
     */
    private static <T extends Comparable<? super T>> void insertionSort(T[] arr, int left, int right) {
        for (int i = left + 1; i <= right; i++) {
            T temp = arr[i];
            int j = i - 1;
            while (j >= 0 && temp.compareTo(arr[j]) < 0) {
                arr[j + 1] = arr[j];
                j--;
            }
            arr[j + 1] = temp;
        }
    }

    private static <T extends Comparable<? super T>> void sort(T[] arr, int left, int right) {
        if (right - left < 7) { //對小規模數據進行插入排序
            insertionSort(arr, left, right);
            return;
        }

        int mid = (left + right) / 2;
        sort(arr, left, mid);
        sort(arr, mid + 1, right);
        merge(arr, left, mid, right);
    }

    public static <T extends Comparable<? super T>> void sort(T[] arr) {
        sort(arr, 0, arr.length - 1);
    }

    private static void printArr(Object[] arr) {
        for (Object o : arr) {
            System.out.print(o);
            System.out.print("\t");
        }
        System.out.println();
    }

    public static void main(String args[]) {
        Integer[] arr = {3, 5, 1, 7, 2, 9, 8, 0, 4, 6};
        printArr(arr);//3   5   1   7   2   9   8   0   4   6
        sort(arr);
        printArr(arr);//0   1   2   3   4   5   6   7   8   9
    }
}

  

歸並排序繼續優化:歸並前判斷一下是否還有必要歸並

public class MergeSort {
    /**
     * @param arr   待排序的數組
     * @param left  本次歸並的左邊界
     * @param mid   本次歸並的中間位置,也就是分界線
     * @param right 本次歸並的右邊界
     * @param <T>   泛型
     * @local aux   輔助空間(Auxiliary Space)
     */
    private static <T extends Comparable<? super T>> void merge(T[] arr, int left, int mid, int right) {
        T[] aux = java.util.Arrays.copyOfRange(arr, left, right + 1);

        //aux,i j分別是這兩半的起始指針。將這兩個閉區間歸並[left ... mid]   [mid + 1 ... right]
        int i = left;
        int j = mid + 1;

        for (int t = left; t <= right; t++) {//把arr數組中的[left...right]區間都覆蓋了,就完事了
            if (i > mid) { //i == mid + 1 時越界(躍出左半數組)
                arr[t] = aux[j++ - left];
            } else if (j > right) {//j == right + 1 時越界(躍出右半數組)
                arr[t] = aux[i++ - left];
            } else if (aux[i - left].compareTo(aux[j - left]) < 0) {//如果i-left小,那麽插入。(左半邊數組的指針所指的數小)
                arr[t] = aux[i++ - left];
            } else { //如果j-left小,那麽插入。(右半邊數組的指針所指的數小)
                arr[t] = aux[j++ - left];
            }
        }
    }

    /**
     * @param arr   當規模小的時候對arr采用插入排序
     * @param left  待排序部分的左邊界
     * @param right 待排序部分的右邊界
     * @param <T>   泛型
     */
    private static <T extends Comparable<? super T>> void insertionSort(T[] arr, int left, int right) {
        for (int i = left + 1; i <= right; i++) {
            T temp = arr[i];
            int j = i - 1;
            while (j >= 0 && temp.compareTo(arr[j]) < 0) {
                arr[j + 1] = arr[j];
                j--;
            }
            arr[j + 1] = temp;
        }
    }

    private static <T extends Comparable<? super T>> void sort(T[] arr, int left, int right) {
//        先註釋掉,為了測試
//        if (right - left < 7) { //對小規模數據進行插入排序
//            insertionSort(arr, left, right);
//            return;
//        }
        if (left >= right) {
            return;
        }

        int mid = (left + right) / 2;
        sort(arr, left, mid);
        sort(arr, mid + 1, right);

        //在歸並前判斷一下,如果左邊的最大的比右邊的最小的還小(或者等於),那就不用歸並了,已經有序了。
        if (arr[mid].compareTo(arr[mid + 1]) <= 0) {
            return;
        }
        merge(arr, left, mid, right);
    }

    public static <T extends Comparable<? super T>> void sort(T[] arr) {
        sort(arr, 0, arr.length - 1);
    }

    private static void printArr(Object[] arr) {
        for (Object o : arr) {
            System.out.print(o);
            System.out.print("\t");
        }
        System.out.println();
    }

    public static void main(String args[]) {
        Integer[] arr = {3, 5, 1, 7, 2, 9, 8, 0, 4, 6};
        printArr(arr);//3   5   1   7   2   9   8   0   4   6
        sort(arr);
        printArr(arr);//0   1   2   3   4   5   6   7   8   9
    }
}

  

歸並排序及優化(Java實現)