交換排序

交互排序思想:在待排序的序列中選擇兩個記錄,將他們的關鍵碼進行比較。若是反序則交互它們的位置。 java

冒泡排序

基本思想:將序列分爲有序區,無序區。每次從無序區冒泡一個最小的記錄。 算法

冒泡過程:從無序區從後往前掃描,兩個相鄰記錄比較,若是後面比前面的小,則交互。 ui

clip_image001

算法分析 指針

clip_image002

冒泡排序-java實現

    /**
     * 將序列分爲兩部分:有序區:無序區 <br>
     * 每趟從無序區 冒泡一個最小的,有序區+1.
     * 穩定的排序
     * 
     * @param arr
     */
    public static void bubble_normal(int[] arr) {
        int size = arr.length;
        for (int i = 0; i < size - 2; i++) {   //n-1輪冒泡
            for (int j = size - 1; j > i; j--) {
                if (arr[j] < arr[j - 1])       // 從後往前,小的記錄往前冒泡
                    MathUtil.swap(arr, j, j - 1);
            }
            System.out.println("第 " + (i + 1) + "輪 :" + Arrays.toString(arr));
        }
    }

冒泡排序的變體orm

    /**
     * 非冒泡排序,也非選擇排序,姑且叫他假冒泡<br>
     * 將序列分爲兩部分:有序區:無序區<br>
     * 每輪排序從無序區找到一個最小記錄,無序區長度-1<br>
     * 
     * 找到一個最小記錄的過程:<br>
     * 用無序區的第一個元素存儲最小記錄。<br>
     * 對比交換:最小記錄>無序區記錄就交換<br>
     * 紀錄在排序過程當中的移動不是冒泡,而是跳躍的交換。不穩定的排序<br>
     * 
     * 缺點:原本位於前面的較小數被交換到後面
     * 
     * @param arr
     */
    public static void bubble_fake(int[] arr) {
        int size = arr.length;
        for (int i = 0; i < size - 2; i++) {//n-1輪
            for (int j = i + 1; j < size; j++) {
                if (arr[j] < arr[i])    //確保arr[i]爲無序區最小的
                    MathUtil.swap(arr, i, j);
            }
            System.out.println("第 " + (i+1) + "輪 :" + Arrays.toString(arr));
        }
    }
    /**
     * 冒泡算法的改進,增長isSwaped標誌<br>
     * 在一輪循環中記錄沒有交互,也就代表序列已經有序的。<br>
     * 當記錄交換(冒泡)則isSwaped=true;說明無序。<br>
     * @param arr
     */
    public static void bubble_optimize(int[] arr) {
        int size = arr.length;
        boolean isSwaped = true;
        for (int i = 0; i < size - 2 && isSwaped; i++) {//n-1輪
            isSwaped = false;                     // 重置狀態
            for (int j = size - 1; j > i; j--) {
                if (arr[j] < arr[j - 1]) {         // 從後往前,小的記錄往前冒泡
                    MathUtil.swap(arr, j, j - 1);
                    isSwaped = true;             // 改變則賦值true
                }
                System.out.println("\t" + Arrays.toString(arr));
            }
            System.out.println("isChanged:" + isSwaped);
            System.out.println("第 " + (i + 1) + "輪 :" + Arrays.toString(arr));
        }
    }

快速排序

基本思想:選擇一個軸值,將待排序列分爲兩個部分,左側記錄均小於軸值,右側記錄均大於軸值。 blog

劃分過程:頭尾兩根指針分別指向劃分區間的頭尾,分別向中間靠攏。 排序

過程當中,若是尾針所指的記錄<軸值,交互,頭指針所指記錄>軸值,交互。這樣就保證了軸值前的全部記錄都小於軸值,軸值以後的記錄都大於軸值。 遞歸

直到兩根指針相遇的位置,即軸值的最終位置。完成劃分。 ip

排序過程:將序列一次劃分後,分別對兩個子序列進行劃分(遞歸處理),直到劃分區間<1 。 get

一次劃分圖示:

clip_image003

算法分析

clip_image004

快速排序-java實現

    /**
     * 劃分區間:arr[first]~arr[end]<br>
     * 右側掃描:直到 尾指針 指向的記錄 小於 軸值,交互,頭指針+1。<br>
     * 左側掃描:直到 頭指針 指向的記錄 大於 軸值,交互,尾指針-1。<br>
     * 頭尾兩根指針相遇,完成劃分。<br>
     * 
     * @param arr
     * @param first 劃分區間的頭指針
     * @param end 劃分區間的頭指針
     * @return
     */
    public static int partition(int[] arr, int first, int end) {
        while (first < end) {//頭尾指針相遇,退出循環,即爲最終的軸值記錄的位置
            while (first < end && arr[first] < arr[end])// 右側掃描
                end--;
            if (first < end) {
                MathUtil.swap(arr, first, end);// 較小記錄交互到前面
                first++;
            }
            //具備操做的對稱性
            while (first < end && arr[first] < arr[end])// 左側掃描
                first++;
            if (first < end) {
                MathUtil.swap(arr, first, end);// 較大記錄交互到後面
                end--;
            }
        }
        return first;
    }
    /**
     * 將序列一次劃分後,分別對兩個子序列進行劃分(遞歸處理),直到劃分區間<1 <br>
     * @param arr
     * @param first
     * @param end
     */
    public static void quickSort(int[] arr,int first, int end){
        if(first<end){//區間長度<1,遞歸結束
            int pivot=partition(arr, first, end);
            quickSort(arr, first, pivot - 1);//遞歸對左側子序列進行快排
            quickSort(arr, pivot + 1, end);  //遞歸對右側子序列進行快排
        }
    }
    
    public static void qsort(int[] arr){
        quickSort(arr, 0, arr.length-1);
    }
相關文章
相關標籤/搜索