選取第K大數的快速選擇算法和注意事項


快速選擇算法,是一種能在大致O(N)的時間內選取數組中第k大或者k小的算法.其基本思路與快速排序算法類似,也是分治的思想.

其實這個算法是個基礎算法,但是不常用,所以今天編的時候錯了POJ2388,才有了這篇文章.

  1. 執行Partition算法(就是那個快排里將區間內所有數划分為小的一部分和大的一部分的過程)
  2. 判斷第k大的數是在小的部分還是大的部分
  3. 遞歸,直到區間足夠小,返回結果

 

下面幾段代碼,尤其要注意的是

while(i<j)

還是

while(i<=j)

程序1:

 

 

不過,就是這樣一個簡單的算法,今天也出了點錯誤,本來我是用用了多少年的快排改的,就像下面這段代碼

程序2:

 

 

幾乎一模一樣,但是下面這樣寫就是是錯的

程序3:

 

 

而這樣寫是對的

程序4:

 

 

 

快速排序已經模板化了,原理也清楚,實現也正確,但是,有些細節有可能理解不到位,所以才會出錯.
下面分析這種情況出現的原因:
出錯其實是一種極端情況,即向右掃描的指針i和向左掃描的指針j重合於k位置;.(這種巧合真的不大常見,但是還是讓我給碰上了,如果沒碰上,估計我的錯誤也不會被糾正.)
 
假設有一個數組arr[]={1,4,3,6,3,2},當k=4時;( 下標從1算起,下同)
QuickSelect細節演示快速選擇算法細節演示
首先,按照Partition算法,先交換arr[2]=4 和arr[6]=2,變成arr[]={1,2,3,6,3,4}
然后i=3,j=5  如圖(1)交換,i++,j–后,i=j=k=4  如圖(2)
  • 按照錯誤的方法(程序3)執行(如圖(3)),函數會在閉區間[1,4]中尋找答案,這樣是錯誤的,因為arr[5]=3不在這個區間內
  • 按照程序1中的方法執行,j會自減1,因為不滿足i<=j(i=4,j=3)然后會在閉區間[4,6]中遞歸(如圖(4)),尋找答案,這樣是正確的
  • 按照程序4中的方法執行,QuickSelect(1,4,4)執行完之后arr[4]=6,這樣,再執行QuickSelect(4,6,4)時,程序會返回正確的結果


免責聲明!

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



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