天天看點

排序二 快速排序要點算法分析完整參考代碼參考資料相關閱讀

要點

快速排序是一種交換排序。

快速排序由C. A. R. Hoare在1962年提出。

它的基本思想是:通過一趟排序将要排序的資料分割成獨立的兩部分:分割點左邊都是比它小的數,右邊都是比它大的數。

然後再按此方法對這兩部分資料分别進行快速排序,整個排序過程可以遞歸進行,以此達到整個資料變成有序序列。

詳細的圖解往往比大堆的文字更有說明力,是以直接上圖:

排序二 快速排序要點算法分析完整參考代碼參考資料相關閱讀

上圖中,示範了快速排序的處理過程:

初始狀态為一組無序的數組:2、4、5、1、3。

經過以上操作步驟後,完成了第一次的排序,得到新的數組:1、2、5、4、3。

新的數組中,以2為分割點,左邊都是比2小的數,右邊都是比2大的數。

因為2已經在數組中找到了合适的位置,是以不用再動。

2左邊的數組隻有一個元素1,是以顯然不用再排序,位置也被确定。(注:這種情況時,left指針和right指針顯然是重合的。是以在代碼中,我們可以通過設定判定條件left必須小于right,如果不滿足,則不用排序了)。

而對于2右邊的數組5、4、3,設定left指向5,right指向3,開始繼續重複圖中的一、二、三、四步驟,對新的數組進行排序。

核心代碼

public int division(int[] list, int left, int right) {

    // 以最左邊的數(left)為基準

    int base = list[left];

    while (left < right) {

        // 從序列右端開始,向左周遊,直到找到小于base的數

        while (left < right && list[right] >= base)

            right--;

        // 找到了比base小的元素,将這個元素放到最左邊的位置

        list[left] = list[right];

        // 從序列左端開始,向右周遊,直到找到大于base的數

        while (left < right && list[left] <= base)

            left++;

        // 找到了比base大的元素,将這個元素放到最右邊的位置

        list[right] = list[left];

    }

    // 最後将base放到left位置。此時,left位置的左側數值應該都比left小;

    // 而left位置的右側數值應該都比left大。

    list[left] = base;

    return left;

}

private void quickSort(int[] list, int left, int right) {

    // 左下标一定小于右下标,否則就越界了

    if (left < right) {

        // 對數組進行分割,取出下次分割的基準标号

        int base = division(list, left, right);

        System.out.format("base = %d:\t", list[base]);

        printPart(list, left, right);

        // 對“基準标号“左側的一組數值進行遞歸的切割,以至于将這些數值完整的排序

        quickSort(list, left, base - 1);

        // 對“基準标号“右側的一組數值進行遞歸的切割,以至于将這些數值完整的排序

        quickSort(list, base + 1, right);

算法分析

快速排序算法的性能

排序類别 排序方法 時間複雜度 空間複雜度 穩定性 複雜性
平均情況 最壞情況 最好情況
交換排序 快速排序 O(Nlog2N) O(N2) 不穩定 較複雜

當資料有序時,以第一個關鍵字為基準分為兩個子序列,前一個子序列為空,此時執行效率最差。

而當資料随機分布時,以第一個關鍵字為基準分為兩個子序列,兩個子序列的元素個數接近相等,此時執行效率最好。

是以,資料越随機分布時,快速排序性能越好;資料越接近有序,快速排序性能越差。

快速排序在每次分割的過程中,需要 1 個空間存儲基準值。而快速排序的大概需要 Nlog2N次的分割處理,是以占用空間也是 Nlog2N 個。

算法穩定性

在快速排序中,相等元素可能會因為分區而交換順序,是以它是不穩定的算法。

完整參考代碼

JAVA版本

代碼實作

排序二 快速排序要點算法分析完整參考代碼參考資料相關閱讀
排序二 快速排序要點算法分析完整參考代碼參考資料相關閱讀

 1 public class QuickSort {

 2  

 3     public int division(int[] list, int left, int right) {

 4         // 以最左邊的數(left)為基準

 5         int base = list[left];

 6         while (left < right) {

 7             // 從序列右端開始,向左周遊,直到找到小于base的數

 8             while (left < right && list[right] >= base)

 9                 right--;

10             // 找到了比base小的元素,将這個元素放到最左邊的位置

11             list[left] = list[right];

12  

13             // 從序列左端開始,向右周遊,直到找到大于base的數

14             while (left < right && list[left] <= base)

15                 left++;

16             // 找到了比base大的元素,将這個元素放到最右邊的位置

17             list[right] = list[left];

18         }

19  

20         // 最後将base放到left位置。此時,left位置的左側數值應該都比left小;

21         // 而left位置的右側數值應該都比left大。

22         list[left] = base;

23         return left;

24     }

25  

26     private void quickSort(int[] list, int left, int right) {

27  

28         // 左下标一定小于右下标,否則就越界了

29         if (left < right) {

30             // 對數組進行分割,取出下次分割的基準标号

31             int base = division(list, left, right);

32  

33             System.out.format("base = %d:\t", list[base]);

34             printPart(list, left, right);

35  

36             // 對“基準标号“左側的一組數值進行遞歸的切割,以至于将這些數值完整的排序

37             quickSort(list, left, base - 1);

38  

39             // 對“基準标号“右側的一組數值進行遞歸的切割,以至于将這些數值完整的排序

40             quickSort(list, base + 1, right);

41         }

42     }

43  

44     // 列印序列

45     public void printPart(int[] list, int begin, int end) {

46         for (int i = 0; i < begin; i++) {

47             System.out.print("\t");

48         }

49         for (int i = begin; i <= end; i++) {

50             System.out.print(list[i] + "\t");

51         }

52         System.out.println();

53     }

54  

55     public static void main(String[] args) {

56         // 初始化一個序列

57         int[] array = {

58                 1, 3, 4, 5, 2, 6, 9, 7, 8, 0

59         };

60  

61         // 調用快速排序方法

62         QuickSort quick = new QuickSort();

63         System.out.print("排序前:\t\t");

64         quick.printPart(array, 0, array.length - 1);

65         quick.quickSort(array, 0, array.length - 1);

66         System.out.print("排序後:\t\t");

67         quick.printPart(array, 0, array.length - 1);

68     }

69 }

View Code

運作結果

排序前:    1  3  4  5  2  6  9  7  8  0 

base = 1: 0  1  4  5  2  6  9  7  8  3 

base = 4:       3  2  4  6  9  7  8  5 

base = 3:       2  3 

base = 6:                5  6  7  8  9 

base = 7:                      7  8  9 

base = 8:                         8  9 

排序後:    0  1  2  3  4  5  6  7  8  9 

參考資料

《資料結構習題與解析》(B級第3版) 

相關閱讀

歡迎閱讀 

程式員的内功——算法

 系列

示例源碼:https://github.com/dunwu/algorithm-notes