圖解快速排序

HHJX發表於2020-12-25


前言

快速排序是應用相當廣泛的排序演算法,在Java的java.util.Arrays這個類裡面的sort()方法就是使用的快速排序,其內部是呼叫了一個類的靜態方法DualPivotQuicksort.sort(),此類實現了Vladimir Yaroslavskiy,Jon Bentley和Josh Bloch的Dual-Pivot Quicksort演算法。 該演算法可在許多資料集上提供O(n log(n))效能,這會導致其他快速排序降級為二次效能,並且通常比傳統的(單軸)Quicksort實現要快。 所有公開的方法都是程式包專用的,旨在在執行任何必要的陣列邊界檢查並將引數擴充套件為所需形式之後從公共方法(在Arrays類中)呼叫.在面試中,也經常要求面試者能手撕快速排序。接下來我們就對快排來一探究竟。

快速排序是什麼?

  • 快速排序演算法是一種分治的排序演算法,是對氣泡排序的一種改進演算法,快速排序的實現核心思想就是對原始陣列進行分而治之,遞迴呼叫,從而實現對陣列的排序,並且時間複雜度與NlogN 成正比。

圖解快速排序

  • 以陣列[7,11,4,3,8,10,2,13,5,14]為例子,一步一步的圖解刨析快速排序。
  • 快速排序的第一步是找到一個基準數,將陣列以這個基準數,分為兩部分,右邊的是小於基準數的,左邊的是大於基準數的。為了方便處理,我們都是以陣列第一個元素作為基準數的。 此時基準數為temp=7.
    在這裡插入圖片描述

第一輪,

① right向左移動,執行right–運算,直到arr[right]小於基準數temp=6時,就暫停移動;left向右移動,執行left++運算,直到arr[left]>temp時,停止移動,然後交換arr[right]和arr[left]的值。
在這裡插入圖片描述

  • ② 重複第一步 在這裡插入圖片描述
  • ③ 比較關鍵的一步來了,此時right繼續左走,走到arr[right]=2時,發現是小於基準數6,這時候停止移動。最最關鍵的來了,那麼此時left還需要繼續走嗎? 答案 是否的。 因為此時left已經和right相遇了,這是終止每一輪的條件,即left<right.
    在這裡插入圖片描述
  • ④ 我們經過第一輪的左右指標移動,比較並交換左右指標的值,這一系列的最終目的就是使得我們的陣列 被分割為兩部分:基準數左邊的數小於 它,而右邊的數要大於它。 那麼緊接著就 將arr[left]與基準數進行交換,就達到了我們的目的。
  • 在這裡插入圖片描述
  • 如此一來,經過第一輪的遍歷交換,我們就將 陣列 基準數的右邊 都小於了它, 左邊都大於它。

第二輪

接下來幹嘛??我們經過第一輪的操作,達成了我們的初步目標,要實現全面排序,後面還得繼續重複第一輪的操作,直到整個陣列完全有序為至。如何重複呢? 我們先從第一輪基準數的右邊開始,分割出陣列[2,5,4,3],重複第一輪的操作。此時的基準數temp=2.

在這裡插入圖片描述

  • ① right 向左移動,直到 遇到 小於等於基準數的值時停止左邊移動。left準備右移動時,已經left==right了 已經滿足 基準數的左邊 大於右邊的要求了,那麼就自我交換一次。並從基準數的右邊開啟第三輪的操作。
    在這裡插入圖片描述

第三輪

  • 依舊重複 第一輪的操作。
    在這裡插入圖片描述
  • ① 初始時right所在的元素已經小於的基準數temp=5了,那麼直接不移動,然後left開始右移動,沿途沒有發現大於基準的元素,因此直到left==right時,停止移動。 並將arr[left]與基準數temp進行交換。在這裡插入圖片描述
    此時 已 temp=7為基準數的陣列的右邊已經完全有序了,那麼繼續對基準數左邊的陣列重複第一輪即可得到完整的排序陣列。
    在這裡插入圖片描述

總結

  • 從整個流程可以發現,快速排序的比較和交換次數比氣泡排序少很多,並且也很少移動元素,這是快速排序比其他排序快的重要因素。但並不意味著,這是最優的快速排序演算法。快速排序的應用實際上還要看具體場景,對於小陣列的排序,當陣列元素小於47時,優先選擇插入排序進行排序。如果要排序的是位元組陣列的長度大於29,則優先使用計數排序而不是插入排序.如果要排序的short或char陣列的長度大於3200,則優先使用計數排序而不是Quicksort.
  • 最後附上 程式碼 僅供參考
  void quieckSort(int [] arr,int start,int end){
        if(start>end)
             return;
        //以第一個元素作為基準數
        int temp=arr[start];
        int left=start;
        int right=end;
        while(left<right){
            //在右邊找到小於基準數的值
            while(left<right&&arr[right]>=temp){
                right--;
            }
            //在左邊找到大於基準數的值
            while(left<right&&arr[left]<=temp){
                left++;
            }
            //交換這兩個值
            if(right>left){
                int t=arr[left];
                arr[left]=arr[right];
                arr[right]=t;
            }
        }
        //基準數的交換
        arr[start]=arr[left];
        arr[left]=temp;
        //遞迴 對 基準數 的左右兩邊繼續快排
        quickSort(arr,start,left-1);
        quickSort(arr,left+1,end);
    }
  • 如果對你有幫助 就點一個贊吧。嘻嘻。

相關文章