快速排序以及基於快排思想的找前k個最大數


  • 快速排序是對冒泡排序的改進。
    • 快速排序是C.R.A.Hoare於1962年提出的一種划分交換排序,它采用一種分治(Divide-and-ConquerMethod)的方法
    • 快速排序的思想:
      • 在數組中找到一個基准數(pivot)
      • 分區,將數組中比基准數大的放到它的右邊,比基准數小的放到它的左邊
      • 繼續對左右區間重復第二步,直到各個區間只有一個數,這時候,數組也就有序了。
    • 代碼:
    •  1 int Partition(vector<int> &v, int head, int rear){
       2     int key = v[head];
       3     while (head < rear){
       4         while (v[rear] <= key && head < rear){
       5             --rear;
       6         }
       7         swap(v[head], v[rear]);
       8         while (v[head] >= key && head < rear){
       9             ++head;
      10         }
      11         swap(v[rear], v[head]);
      12         
      13     }
      14     v[head] = key;
      15     ++my_count;
      16     return head;
      17 }
      18 
      19 void QuickSort(vector<int> &v, int head, int rear){
      20     int pivot = -1;
      21     if (head < rear){
      22         pivot = Partition(v, head, rear);
      23         QuickSort(v, head, pivot - 1);
      24         QuickSort(v, pivot + 1, rear);
      25     }
      26 }
    • Note: Partition函數中 v[rear] <= key 以及 v[head] >= key 表達式必須包含等於的判斷,否則當數組兩頭的數相等時將會造成死循環  例如 {5,2,6,2,9,10,5}
    • Partition函數:最慢情況下快速排序會進行 size()- 1 次 Partition函數,而每次調用,Partition函數會選擇一個基准數,例如v[head]或者v[rear],或者任意一個數組中的數。之后分別從兩頭掃描,碰到比基准數大或者小的數就與上一個head或rear交換,或者直到head大於等於rear時,此次循環結束。
    • QuickSort函數:該函數采用遞歸的方法,每次調用一次Partition函數,得到一個基准數的索引和相對基准數有序的數列,之后將該基准數左邊的數組和右邊的數組分別調用QuickSort函數,也就是它本身。直到數組中只有一個數時,這條遞歸序列便結束。
  • 基於快速排序的查找前k個最大數
    • 由上可知,快排的思想是每次找到一個基准數,將數組排列成基准數左邊的每個數都比基准數大,右邊的每個數都比基准數小的序列。
    • 通過這個思想,我們可以稍微修改QuickSort函數,使它變成QuickSearch函數,使之擁有快速查找前k個最大的數。
    •  1 int QuickSearch(vector<int> &v, int head, int rear, int k){
       2     int pivot = -1, len = 0;
       3     if (head < rear){
       4         pivot = Partition(v, head, rear);
       5         len = pivot - head + 1;
       6         if (len < k){
       7             pivot = QuickSearch(v, pivot + 1, rear, k - len);
       8         }
       9         else if (len > k){
      10             pivot = QuickSearch(v, head, pivot - 1, k);
      11         }
      12     }
      13     return pivot;
      14 }
    • 上圖中,我們可以發現,函數參數多了一個k,這個值是表示要獲取前k個最大數。
    • 函數中多了一些邏輯,每次執行完Partition函數,根據獲取的基准值索引,計算基准值左邊數組的長度。
    • len < k,則說明,在基准值左邊的數組中已經有了len個最大數,此時,我們只需在基准值右邊的數組再找k - len個最大數即可,所以只要再次調用QuickSearch函數,並傳入k-len參數以及基准值右邊的數組索引。
    • len > k,則說明,此時基准值左邊已經有了len個最大值,然而len大於k,我們並不需要那么多的最大值,所以再次調用QuickSearch函數,傳入基准值左邊的數組索引,以及k,獲得這個長度len的最大數集的子集


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM