生活随笔
收集整理的這篇文章主要介紹了
分治法--线性时间选择
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
【分治法】線性時間選擇
? ? ??? ??線性時間選擇問題:給定線性序集中n個元素和一個整數k,1≤k≤n,要求找出這n個元素中第k小的元素,(這里給定的線性集是無序的)。
? ? ? ?1、隨機劃分線性選擇
? ? ? ?線性時間選擇隨機劃分法可以模仿隨機化快速排序算法設計。基本思想是對輸入數組進行遞歸劃分,與快速排序不同的是,它只對劃分出的子數組之一進行遞歸處理。
? ? ? ?程序清單如下:
[cpp]?view plaincopy
?? #include?"stdafx.h"?? #include?<iostream>??? #include?<ctime>?? using?namespace?std;??? ?? int?a[]?=?{5,7,3,4,8,6,9,1,2};?? ?? template?<class?Type>?? void?Swap(Type?&x,Type?&y);?? ?? inline?int?Random(int?x,?int?y);?? ?? template?<class?Type>?? int?Partition(Type?a[],int?p,int?r);?? ?? template<class?Type>?? int?RandomizedPartition(Type?a[],int?p,int?r);?? ?? template?<class?Type>?? Type?RandomizedSelect(Type?a[],int?p,int?r,int?k);?? ?? int?main()?? {?? ????for(int?i=0;?i<9;?i++)?? ????{?? ????????cout<<a[i]<<"?";?? ????}?? ????cout<<endl;?? ????cout<<RandomizedSelect(a,0,8,3)<<endl;?? }?? ?? template?<class?Type>?? void?Swap(Type?&x,Type?&y)?? {?? ????Type?temp?=?x;?? ????x?=?y;?? ????y?=?temp;?? }?? ?? inline?int?Random(int?x,?int?y)?? {?? ?????srand((unsigned)time(0));?? ?????int?ran_num?=?rand()?%?(y?-?x)?+?x;?? ?????return?ran_num;?? }?? ?? template?<class?Type>?? int?Partition(Type?a[],int?p,int?r)?? {?? ????int?i?=?p,j?=?r?+?1;?? ????Type?x?=?a[p];?? ?? ????while(true)?? ????{?? ????????while(a[++i]<x?&&?i<r);?? ????????while(a[--j]>x);?? ????????if(i>=j)?? ????????{?? ????????????break;?? ????????}?? ????????Swap(a[i],a[j]);?? ????}?? ????a[p]?=?a[j];?? ????a[j]?=?x;?? ????return?j;?? }?? ?? template<class?Type>?? int?RandomizedPartition(Type?a[],int?p,int?r)?? {?? ????int?i?=?Random(p,r);?? ????Swap(a[i],a[p]);?? ????return?Partition(a,p,r);?? }?? ?? template?<class?Type>?? Type?RandomizedSelect(Type?a[],int?p,int?r,int?k)?? {?? ????if(p?==?r)?? ????{?? ????????return?a[p];?? ????}?? ????int?i?=?RandomizedPartition(a,p,r);?? ????int?j?=?i?-?p?+?1;?? ????if(k?<=?j)?? ????{?? ????????return?RandomizedSelect(a,p,i,k);?? ????}?? ????else?? ????{?? ?????????? ?????????? ????????return?RandomizedSelect(a,i+1,r,k-j);?? ????}?? }?? ? ? ? ?程序解釋:利用隨機函數產生劃分基準,將數組a[p:r]劃分成兩個子數組a[p:i]和a[i+1:r],使a[p:i]中的每個元素都不大于a[i+1:r]中的每個元素。接著"j=i-p+1"計算a[p:i]中元素個數j.如果k<=j,則a[p:r]中第k小元素在子數組a[p:i]中,如果k>j,則第k小元素在子數組a[i+1:r]中。注意:由于已知道子數組a[p:i]中的元素均小于要找的第k小元素,因此,要找的a[p:r]中第k小元素是a[i+1:r]中第k-j小元素。
? ? ? 在最壞的情況下,例如:總是找到最小元素時,總是在最大元素處劃分,這是時間復雜度為O(n^2)。但平均時間復雜度與n呈線性關系,為O(n)(數學證明過程略過,可參考王云鵬論文《線性時間選擇算法時間復雜度深入研究》)。
? ? ? 2、利用中位數線性時間選擇
? ? ??中位數:是指將數據按大小順序排列起來,形成一個數列,居于數列中間位置的那個數據。
? ? ? 算法思路:如果能在線性時間內找到一個劃分基準使得按這個基準所劃分出的2個子數組的長度都至少為原數組長度的ε倍(0<ε<1),那么就可以在最壞情況下用O(n)時間完成選擇任務。例如,當ε=9/10,算法遞歸調用所產生的子數組的長度至少縮短1/10。所以,在最壞情況下,算法所需的計算時間T(n)滿足遞推式T(n)<=T(9n/10)+O(n)。由此可得T(n)=O(n)。
? ? ?實現步驟:
? ? ? (1)將所有的數n個以每5個劃分為一組共組,將不足5個的那組忽略,然后用任意一種排序算法,因為只對5個數進行排序,所以任取一種排序法就可以了。將每組中的元素排好序再分別取每組的中位數,得到個中位數。
? ? ? (2)取這個中位數的中位數,如果是偶數,就找它的2個中位數中較大的一個作為劃分基準。
? ? ? (3)將全部的數劃分為兩個部分,小于基準的在左邊,大于等于基準的放右邊。在這種情況下找出的基準x至少比個元素大。因為在每一組中有2個元素小于本組的中位數,有個小于基準,中位數處于,即個中位數中又有個小于基準x。因此至少有個元素小于基準x。同理基準x也至少比個元素小。而當n≥75時≥n/4所以按此基準劃分所得的2個子數組的長度都至少縮短1/4。
? ? ??
? ? ? ?程序清單如下:
[cpp]?view plaincopy
?? #include?"stdafx.h"?? #include?<ctime>?? #include?<iostream>??? using?namespace?std;??? ?? template?<class?Type>?? void?Swap(Type?&x,Type?&y);?? ?? inline?int?Random(int?x,?int?y);?? ?? template?<class?Type>?? void?BubbleSort(Type?a[],int?p,int?r);?? ?? template?<class?Type>?? int?Partition(Type?a[],int?p,int?r,Type?x);?? ?? template?<class?Type>?? Type?Select(Type?a[],int?p,int?r,int?k);?? ?? int?main()?? {?? ?????? ????int?a[100];?? ?? ?????? ????srand((unsigned)time(0));?? ?? ????for(int?i=0;?i<100;?i++)?? ????{?? ????????a[i]?=?Random(0,500);?? ????????cout<<"a["<<i<<"]:"<<a[i]<<"?";?? ????}?? ????cout<<endl;?? ?? ????cout<<"第83小元素是"<<Select(a,0,99,83)<<endl;?? ?? ?????? ????BubbleSort(a,0,99);?? ?? ????for(int?i=0;?i<100;?i++)?? ????{?? ????????cout<<"a["<<i<<"]:"<<a[i]<<"?";?? ????}?? ????cout<<endl;?? }?? ?? template?<class?Type>?? void?Swap(Type?&x,Type?&y)?? {?? ????Type?temp?=?x;?? ????x?=?y;?? ????y?=?temp;?? }?? ?? inline?int?Random(int?x,?int?y)?? {?? ?????int?ran_num?=?rand()?%?(y?-?x)?+?x;?? ?????return?ran_num;?? }?? ?? ?? template?<class?Type>?? void?BubbleSort(Type?a[],int?p,int?r)?? {?? ??????? ?????bool?exchange;???? ?????for(int?i=p;?i<=r-1;i++)???? ?????{???? ????????exchange?=?false?;???? ????????for(int?j=i+1;?j<=r;?j++)???? ????????{???? ????????????if(a[j]<a[j-1])???? ????????????{???? ????????????????Swap(a[j],a[j-1]);??? ????????????????exchange?=?true;???? ????????????}????? ????????}????? ?????????? ????????if(false?==?exchange)???? ????????{?? ?????????????break?;???? ????????}?? ?????}?? }?? ?? template?<class?Type>?? int?Partition(Type?a[],int?p,int?r,Type?x)?? {?? ????int?i?=?p-1,j?=?r?+?1;?? ?? ????while(true)?? ????{?? ????????while(a[++i]<x?&&?i<r);?? ????????while(a[--j]>x);?? ????????if(i>=j)?? ????????{?? ????????????break;?? ????????}?? ????????Swap(a[i],a[j]);?? ????}????? ????return?j;?? }?? ?? ?? template?<class?Type>?? Type?Select(Type?a[],int?p,int?r,int?k)?? {?? ????if(r-p<75)?? ????{?? ????????BubbleSort(a,p,r);?? ????????return?a[p+k-1];?? ????}?? ?????? ????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]);?? ????}?? ?????? ????Type?x?=?Select(a,p,p+(r-p-4)/5,(r-p-4)/10);?? ????int?i?=?Partition(a,p,r,x);?? ????int?j?=?i-p+1;?? ????if(k<=j)?? ????{?? ????????return?Select(a,p,i,k);?? ????}?? ????else?? ????{?? ????????return?Select(a,i+1,r,k-j);?? ????}?? }?? ? ? ? ? ? ?運行結果如下:
總結
以上是生活随笔為你收集整理的分治法--线性时间选择的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。