[圖解算法]線性時間選擇Linear Select——<遞歸與分治策略>


  1 #include <ctime> 
  2 #include <iostream>   
  3 using namespace std;   
  4   
  5 template <class Type>  
  6 void Swap(Type &x,Type &y);  
  7   
  8 inline int Random(int x, int y);  
  9   
 10 template <class Type>  
 11 void BubbleSort(Type a[],int p,int r);  
 12   
 13 template <class Type>  
 14 int Partition(Type a[],int p,int r,Type x);  
 15   
 16 template <class Type>  
 17 Type Select(Type a[],int p,int r,int k);  
 18   
 19 void main()  
 20 {  
 21     //初始化數組  
 22     int a[100];  
 23   
 24     //必須放在循環體外面  
 25     srand((unsigned)time(0));  
 26   
 27     for(int i=0; i<100; i++)  
 28     {  
 29         a[i] = Random(0,100);  
 30         cout<<"a["<<i<<"]:"<<a[i]<<" ";  
 31     }  
 32     cout<<endl; 
 33 
 34     cout<<"第23小元素是"<<Select(a,0,99,23)<<endl;  
 35   
 36 
 37     //重新排序,對比結果  
 38     BubbleSort(a,0,99);  
 39     for(i=0; i<100; i++)  
 40     {  
 41         cout<<"a["<<i<<"]:"<<a[i]<<" ";  
 42     }  
 43     cout<<endl;  
 44 }  
 45   
 46 template <class Type>  
 47 void Swap(Type &x,Type &y)  
 48 {  
 49     Type temp = x;  
 50     x = y;  
 51     y = temp;  
 52 }  
 53   
 54 inline int Random(int x, int y)  
 55 {  
 56      int ran_num = rand() % (y - x) + x;  
 57      return ran_num;  
 58 }  
 59   
 60 //冒泡排序  
 61 template <class Type>  
 62 void BubbleSort(Type a[],int p,int r)  
 63 {  
 64      //記錄一次遍歷中是否有元素的交換     
 65      bool exchange;    
 66      for(int i=p; i<r;i++)    
 67      {    
 68         exchange = false ;    
 69         for(int j=0; j<=r-i; j++)    
 70         {    
 71             if(a[j]<a[j-1])    
 72             {    
 73                 Swap(a[j],a[j-1]);   
 74                 exchange = true;    
 75             }     
 76         }     
 77         //如果這次遍歷沒有元素的交換,那么排序結束     
 78         if(false == exchange)    
 79         {  
 80              break ;    
 81         }  
 82      }  
 83 }  
 84   
 85 template <class Type>  
 86 int Partition(Type a[],int p,int r,Type x)  
 87 {  
 88     int i = p-1,j = r + 1;  
 89   
 90     while(true)  
 91     {  
 92         while(a[++i]<x && i<r);  
 93         while(a[--j]>x);  
 94         if(i>=j)  
 95         {  
 96             break;  
 97         }  
 98         Swap(a[i],a[j]);  
 99     }     
100     return j;  
101 }  
102   
103   
104 template <class Type>  
105 Type Select(Type a[],int p,int r,int k)  
106 {  
107     if(r-p<75)  
108     {  
109         BubbleSort(a,p,r);  
110         return a[p+k-1];  
111     }  
112     //(r-p-4)/5相當於n-5  
113     for(int i=0; i<=(r-p-4)/5; i++)  
114     {  
115         //將元素每5個分成一組,分別排序,並將該組中位數與a[p+i]交換位置  
116         //使所有中位數都排列在數組最左側,以便進一步查找中位數的中位數  
117         BubbleSort(a,p+5*i,p+5*i+4);  
118         Swap(a[p+5*i+2],a[p+i]);  
119     }  
120     //找中位數的中位數  
121     Type x = Select(a,p,p+(r-p-4)/5,(r-p-4)/10);  
122     i = Partition(a,p,r,x);  
123     int j = i-p+1;  
124     if(k<=j)  
125     {  
126         return Select(a,p,i,k);  
127     }  
128     else  
129     {  
130         return Select(a,i+1,r,k-j);  
131     }  
132 }  
View Code

提醒:此篇需要先理解快速排序。

[圖解+例子]

一、建立隨機數組

 

(共27個數)(代碼中為100個數,為了放得下舉的例子改為27個)


 

 

二、給線性時間選擇函數Select()傳參

Type a[]  數組a

int p  起始位置

int r   結束位置

int k   查找第k小


 

 

三、判斷

元素個數<75  不需要線性選擇--》直接進行冒泡排序返回a[p+k-1](第k小元素)

元素個數>75   進行線性選擇  --》進行下一步


 

 

四、線性時間選擇

 

  1- 分組並取各組中位數 (將元素每5個分成一組,分別排序,並將該組中位數與a[p+i]交換位置 )【圖中綠線12345表示要交換的一對對數據】

  for(int i=0; i<=(r-p-4)/5; i++)
  {
  BubbleSort(a,p+5*i,p+5*i+4);
  Swap(a[p+5*i+2],a[p+i]);
  }

 
  目的:使所有組的中位數都排列在數組最左側,以便進一步查找中位數的中位數 

 

 

 

 

  2- 查找中位數的中位數 

  Type x = Select(a , p , p+(r-p-4)/5 , (r-p-4)/10 ); 

  p到p+(r-p-4)/5為中位數的范圍,p+(r-p-4)/5  ÷  2   =   (r-p-4)/10-->中位數的中位數

 ----------------------------------------------------------------------------------------------------------

  

  3-用找到的中位數的中位數做為快速排序的標准進行一趟快速排序(前面有篇講的快速排序為了方便直接用第一個做標准,也有用隨機數做標准的)

  i = Partition(a,p,r,x);

  排序結束后,標准元素將數組分為三部分:左,標准元素,右。

  快排講過啦,這里快速排序省略圖解啦 !想看點這里 快速排序

 ------------------------------------------------------------------------------------------------------------

  4-判斷 

  快速排序后看成三部分:左,標准元素,右。

  左都比標准元素小,右都比它大;(此時左右還是亂序,只有標准元素找到了它最終應該排的位置,這里不清晰先看快速排序那篇文章

  所以判斷下我們要找的第k小是比它大(在右)還是比它小(在左);

  int j = i-p+1;
  if(k<=j)
  {
    return Select(a,p,i,k);
  }
  else
  {
    return Select(a,i+1,r,k-j);
  }

  i為快速排序返回值,j = i - 起始位置 + 1;

  小於或者等於,對左半段重復上述操作(遞歸);

  反之,對右半段。

  -----------------------------------------------------------------------------------------------------------------

[特例]

有空更新。。。

[總結]

線性時間選擇其實就是————>>快速排序的加強版,

快速排序中的標准元素變為————>>分組后取得的各組中位數的中位數。

所以多了一步取中位數的操作而已。

 

本人保留解析著作權。

算法引用自 王曉東. 計算機算法設計與分析[M]. 電子工業出版社, 2012.

 


免責聲明!

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



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