實現快速排序算法的另一種思路

一、快速排序算法

快速排序的基本思想如下:

  1. 從數組中取出一個數作爲中軸數(pivot)
  2. 劃分數組:將比這個數大的數放到它的右邊,小於或等於它的數放到它的左邊
  3. 再對左右區間重複上述步驟,直到各區間只有一個數在這裏插入圖片描述
    本篇文章實現快速排序算法的主要思路是:
    1) 定義兩個前向指針i,j,i記錄小於中軸數的分區,通過指針j遍歷數組,並將每個j位置的元素和pivot(中軸數)進行比較,arr[j] 小於 pivot 時,將arr[j]和arr[i] 交換位置,否則j直接後移繼續下一個元素的遍歷;
    2) 最後將pivot和i-1位置(i前面的元素都小於中軸數)的數據交換;
    3) 遞歸。

二、實例排序分析

樣本數據:{5,8,4,3,2,5,7,9}

  • 中軸數pivot: 一般取待排序序列的第一個(當然這個數可以選一個能讓數組均勻分佈的數)
  • 目標: 交換後, 中軸數左邊的數要全部小於中軸數, 其右邊的數要全部大於等於中軸數
    在這裏插入圖片描述
    步驟如下:
  • 定義兩個指針 i,j,從中軸數後一位開始,即start+1的位置;
  • 通過j對數組進行循環遍歷,並每次和中軸數比較,小於中軸數則將arr[j] 和arr[i]數據交換,同時i++,指向後一位置;大於中軸數則繼續下一個元素比較;
  • 如第一次遍歷比較後(8>5),只對j後移在這裏插入圖片描述
    第二次比較後(4<5),4和8交換位置,同時i++,j++:
    在這裏插入圖片描述
    第一輪循環遍歷後的結果如下:
    在這裏插入圖片描述
    此時將start位置的pivot和i-1位置的數據交換:
    在這裏插入圖片描述
  • 至此,以中軸數分爲3部分,左邊的都比其小,右邊的都比其大。

對於左右兩部分數據再通過遞歸分別進行快速排序。

三、算法實現

實現代碼如下:

/**
 * 兩個先後指針實現快排
 */
public class QuickSort {
   
    public void sort(int[] arr) {
        if(arr == null || arr.length <= 1) {
            return;
        }
        sortHelper(arr, 0, arr.length-1);
    }

    private void sortHelper(int[] arr, int start, int end) {
        if(start >= end){
            return;
        }
        // 分治
        int middle = partition(arr, start, end);
        // 左右部分進行遞歸
        sortHelper(arr, start, middle - 1);
        sortHelper(arr, middle+1, end);
    }

    private int partition(int[] arr, int start, int end) {
        // 選一箇中軸數 pivot, 一般選第一個數即可
        int pivot = arr[start];

        int i = start + 1; // 從第二個數開始循環比較
        for(int j=start+1; j <= end; j++){
            if(arr[j] < pivot){
                swap(arr, i, j);
                i++;
            }
            SortUtils.printArray(arr);
        }

        // 第i 個數爲大於pivot 的數, 將pivot 和i 的前一位置交換
        swap(arr, start, i-1);

        // 返回pivot位置
        return i-1;
    }

    private void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

    /**
	 * 數組打印
	 * @param arr
	 */
	public static void printArray(int arr[])  { 
        int n = arr.length; 
        for (int i=0; i<n; ++i) 
            System.out.print(arr[i] + " "); 
        System.out.println(); 
    } 
    
    public static void main(String[] args) {
        int[] arrayToSort = {5,8,4,3,2,5,7,9};
        printArray(arrayToSort);
        int[] arrayClone = Arrays.copyOf(arrayToSort, arrayToSort.length);
     
        Sorter sorter = new QuickSort();
        sorter.sort(arrayToSort);
        printArray(arrayToSort);
        
         // jdk 排序
        Arrays.sort(arrayClone);
        System.out.println("jdk Arrays.sort排序結果:");
        printArray(arrayClone);
    }

}

運行結果:

5 8 4 3 2 5 7 9 
5 8 4 3 2 5 7 9 
5 4 8 3 2 5 7 9 
5 4 3 8 2 5 7 9 
5 4 3 2 8 5 7 9 
5 4 3 2 8 5 7 9 
5 4 3 2 8 5 7 9 
5 4 3 2 8 5 7 9 
2 4 3 5 8 5 7 9 
2 4 3 5 8 5 7 9 
2 4 3 5 8 5 7 9 
2 3 4 5 8 5 7 9 
2 3 4 5 8 5 7 9 
2 3 4 5 8 5 7 9 
2 3 4 5 7 5 8 9 
排序結果:
2 3 4 5 5 7 8 9 
jdk 排序結果:
2 3 4 5 5 7 8 9 

由於快排需要交換元素順序,不保證相同元素的起始先後順序,所以快排是不穩定排序。

注: 快速排序的最好的情況(每次數據劃分得很均勻)時間複雜度爲O(nlogn),最壞的情況(需排序的數據爲正序或逆序排列時)複雜度爲O(n^2)。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章