歸并排序、快速排序

歸并排序


不斷地講無序數(shù)組分成兩部分比較

將數(shù)組分成兩部分,
分割成的兩部分若能再次對半拆分,就繼續(xù)重復(fù)步驟
然后當(dāng)拆分為一個元素時再次歸并到上個拆份的數(shù)組


實現(xiàn):

import java.util.Arrays;


public class MergeSort {
    /**
     *
     * @param arr
     * @param l 數(shù)組最左邊的元素
     * @param mid 中間歸并的分隔
     * @param r 數(shù)組最右邊的元素
     */
//    如何歸并
    public static void merge(int[] arr,int l, int mid, int r){
        int[] aux = Arrays.copyOfRange(arr, l, r + 1);

//        設(shè)置兩個指針指向分開數(shù)組的頭尾
        int i = l,j = mid + 1;
        for (int k = l; k <= r; k++) {

            //左數(shù)組越界問題解決
            if (i > mid){
                arr[k] = aux[j-l];
                j++;
            }
            //右數(shù)組越界問題解決
            else if (j > r){
                arr[k] = aux[i-l];
                i++;
            }
            else if (aux[i-l] < aux[j-l]){
                arr[k] = aux[i-l];
                i++;
            }
            else{
                arr[k] = aux[j-l];
                j++;
            }
        }

    }

//    定義歸并的方法
//    將原來的數(shù)組進(jìn)行分割
    private static void sort(int[] arr,int l, int r){
        if (l >= r){
            return;
        }

        int mid = (l+r) / 2;

//        這里遞歸調(diào)用將數(shù)組分割到最小
        sort(arr, l, mid);
        sort(arr, mid+1, r);
//        分割后執(zhí)行遞歸
        merge(arr, l, mid, r);
    }

    public static void sort(int[] arr){

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

    public static void main(String[] args) {
        int[] arr = {5,8,1,4,3};
        MergeSort.sort(arr);
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i]);
        }
    }
}

優(yōu)化在近乎有序數(shù)組時歸并排序的效率

private static void sort(int[] arr,int l,int r){

        if (l>=r){
            return;
        }

        int mid = (l+r)/2;
        sort(arr, l, r);
        sort(arr, mid + 1, r);
        if ( arr[mid] > arr[mid+1] ){
            merge(arr, l, mid, r);//優(yōu)化在近乎有序數(shù)組時用歸并排序時的效率
            //因為歸并排序左邊數(shù)組的最后一位元素小于右邊第一位的時候已經(jīng)確定了有序
        }

    }

歸并排序在于用空間換取時間,需要另外開辟新的數(shù)組空間來進(jìn)行歸并

快速排序



如何進(jìn)行取值分割(Partition)



實現(xiàn):

public class QuickSort {

    public static void sort(int[] arr){
        int n = arr.length;
        quickSort(arr, 0, n-1);
    }

    private static void quickSort(int[] arr,int l,int r){
        if (l >= r){
            return;
        }
        //其實也是j
        int p = partition(arr,l,r);
        quickSort(arr, l, p-1);
        quickSort(arr, p+1, r);
    }

    private static int partition(int[] arr, int l, int r) {
//        先取出一個比較數(shù)
        int v = arr[l];
//        l+1是開始排列的第一個元素
        int j = l;//表示大于v元素區(qū)域一開始為空
//        i是當(dāng)前訪問的元素
        for (int i = l+1; i < r ; i++) {
//            若i位置的元素小于v,則j會指向此區(qū)域
            if ( arr[i] < v){
//                與j+1位置的元素互換
//             第一種寫法:
                swap(arr,arr[j+1],arr[i]);
                j++;

//                第二種寫法:
//                swap(arr,arr[++j],arr[i]);
            }
        }
        swap(arr,arr[l],arr[j]);
        return j;
    }

    private static void swap(int[] arr, int i, int j) {

        int temp = arr[j];
        arr[j] = arr[i];
        arr[i] = temp;
    }

    public static void main(String[] args) {
        int[] arr = {5,8,1,4,3};
        MergeSort.sort(arr);
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i]);
        }
    }
}

為了避免當(dāng)數(shù)組近乎是有序或有大量重復(fù)時

雙路排序



實現(xiàn):

private static int partition(Comparable arr[],int l,int r){

        //選擇一個隨機數(shù)與第一個元素交換
        swap(arr, l, (int)(Math.random()*(r-l+1))+l);

        //拿出第一個元素做對比
        Comparable v = arr[l];

        //設(shè)i和j分別為左數(shù)組和右數(shù)組添加元素時指針
        int i = l+1,j=r;

        while (true){
            //若左數(shù)組下個元素小于v則考察下一個元素
            while(i<=r && arr[i].compareTo(v) <0){
                i++;
            }

            //若右數(shù)組下個元素大于v則考察下一個元素
            while(j<=l+1 && arr[j].compareTo(v) >0){
                j--;
            }
            //直到i>j時說明已經(jīng)考察到了所有元素
            if(i>j){
                break;
            }

            //當(dāng)兩個while循環(huán)都不滿足條件時
            //交換兩個數(shù)組的最后一個元素使之滿足v<i與v>j的條件
            swap(arr, i, j);
            i++;
            j--;
        }

        swap(arr, l, j);
        return j;
    }

三路排序



實現(xiàn):

    private static void partition(Comparable arr[],int l,int r){

        //選擇一個隨機數(shù)與第一個元素交換
        swap(arr, l, (int)(Math.random()*(r-l+1))+l);

        //拿出第一個元素做對比
        Comparable v = arr[l];

        int lt = l;     // arr[l+1...lt] < v 指向<v的最后一個元素
        int gt = r + 1; // arr[gt...r] > v
        int i = l+1;    // arr[lt+1...i) == v 作為考察元素指針

        //i<gt則說明元素還為考察到最后一個
        while (i < gt){
            if(arr[i].compareTo(v) < 0){
                swap(arr, i,lt+1);
                lt++;
                i++;
            }
            else if( arr[i].compareTo(v) > 0 ){
                swap( arr, i, gt-1);
                gt --;
            }
            else{ // arr[i] == v
                i ++;
            }
        }
        swap( arr, l, lt );

        sort(arr, l, lt-1);
        sort(arr, gt, r);
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容