
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 }
提醒:此篇需要先理解快速排序。
[圖解+例子]
一、建立隨機數組
(共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.