递归算法学习系列之寻找第K大
????????國人向來喜歡論資排輩的,每個人都想當(dāng)老大,實(shí)在當(dāng)不成,當(dāng)個老二,老三,老K也不錯,您一定看過這樣的爭論: 兩個人吵架,一個人非常強(qiáng)勢,另外一個忍受不住了便說:"你算老幾呀?",下面就通過這篇文章就是要解決找出老幾的問題!
??? 2.?? 應(yīng)用場景
??????? 在向量V[first,last)中查找出第K大元素的值
??? 3.? 分析
??????? 如果利用排序算法將向量V排好序,那么第K大元素就是索引為v.length-k的元素了,這樣能解決問題,但效率不高,因?yàn)檫@相當(dāng)于為了殲滅敵人一個小隊而動用了我們?nèi)姷牧α?#xff0c;得不償失,回想快速排序中的分表,每次都將目標(biāo)向量分為兩個子表,左子表中全部小于中間元素v[mid],右邊都大于中間元素v[mid],這樣就可以減小了查找范圍,因?yàn)槲铱梢灾徊檎易笞颖砘蛘哂易颖砭湍苷业侥繕?biāo)元素了。如下圖所示,我們可以將向量 v劃分成如下
| ? Left(<=KLargest) | KLargest | ??? Right(>=KLargest) |
按照這樣的思路,我們?nèi)允褂每焖倥判蛑械姆直聿呗?#xff0c;首先將向量V從中間位置分開,分成左和右,分好后,中間值的索引如果恰恰等于K,就找到了,否則如果中間元素索引大于K,則在左子表中繼續(xù)查找,忽略右子表,如果中間值索引小于K,則在右子表中繼續(xù)查找,如此循環(huán)往復(fù)。
快速排序中的子表劃分函數(shù)為:
??/**////?<summary>????????///?交換位置
????????///?</summary>
????????///?<param?name="v"></param>
????????///?<param?name="index1"></param>
????????///?<param?name="index2"></param>
????????private?void?Swrap(int[]?v,?int?index1,?int?index2)
????????{
????????????int?temp?=?v[index1];
????????????v[index1]?=?v[index2];
????????????v[index2]?=?temp;
????????}
????????/**////?<summary>
????????///?將向量V中索引{first,last)劃分成兩個左子表和右子表
????????///?</summary>
????????///?<param?name="v">向量V</param>
????????///?<param?name="first">開始位置</param>
????????///?<param?name="last">結(jié)束位置</param>
????????private?int?PivotIndex(int[]?v,?int?first,?int?last)
????????{
????????????if?(last?==?first)
????????????{
????????????????return?last;
????????????}
????????????if?(last?-?first?==?1)
????????????{
????????????????return?first;
????????????}
????????????int?mid?=?(first?+?last)?/?2;
????????????int?midVal?=?v[mid];
????????????//交換v[first]和v[mid]
????????????Swrap(v,?first,?mid);
????????????int?scanA?=?first?+?1;
????????????int?scanB?=?last?-?1;
????????????for?(;?;?)
????????????{
????????????????while?(scanA?<=?scanB?&&?v[scanA]?<?midVal)
????????????????{
????????????????????scanA++;
????????????????}
????????????????while?(scanB?>?first?&&?midVal?<=?v[scanB])
????????????????{
????????????????????scanB--;
????????????????}
????????????????if?(scanA?>=?scanB)
????????????????{
????????????????????break;
????????????????}
????????????????Swrap(v,?scanA,?scanB);
????????????????scanA++;
????????????????scanB--;
????????????}
????????????Swrap(v,?first,?scanB);
????????????return?scanB;
????????}
???設(shè)計一個函數(shù),FindKLargest(int[] v,int first,int last,int k);這個函數(shù)包括四個參數(shù):向量V,開始位置first,結(jié)束位置last,和第k大中的K,則該函數(shù)為:
調(diào)用FindKLargest后,因?yàn)閿?shù)組是從小到大排序,所以第K大元素的值為V[v.Length-k];
????????{
????????????//表示分表中值的索引
????????????int?index?=?0;
????????????index?=?PivotIndex(v,?first,?last);
????????????if?(index?==?k)
????????????{
????????????????//找到了K大
????????????????return;
????????????}
????????????if?(index?>?k)
????????????{
????????????????//只在左子表中查找
????????????????FindKLargest(v,?first,?index,?k);
????????????}
????????????else
????????????{
????????????????//只在右子表中查找
????????????????FindKLargest(v,?index,?last,?k);
????????????}
????????}
4.運(yùn)行結(jié)果:
? 原向量 :v? = {?100, 200, 50, 23, 300, 560, 789, 456, 123, 258}?
? first = 0; last = v.Length;k=3
? 輸出:456
5.結(jié)論
? 利用遞歸算法可以將比較復(fù)雜的問題劃分為越來越小的小問題,這樣能夠使復(fù)雜問題簡單化,這樣的思路在系統(tǒng)設(shè)計和架構(gòu)中同樣有著至關(guān)重要的作用,一個好的架構(gòu)師,面對復(fù)雜的問題,能庖丁解牛般化腐朽為神奇,而壞的卻往往適得其反,他們的特長是簡單問題復(fù)雜化。
6.? 項(xiàng)目文件
?? /Files/jillzhang/FindK.rar
?
?? 上幾篇文章索引:?
??? 1.算法:【一列數(shù)的規(guī)則如下: 1、1、2、3、5、8、13、21、34 ,求第30位數(shù)是多少, 用遞歸算法實(shí)現(xiàn)。(C#語言)】
??? 2.大牛生小牛的問題?
????3.遞歸算法學(xué)習(xí)系列一(分而治之策略)
??? 4. 遞歸算法學(xué)習(xí)系列二(歸并排序)
??? 5.遞歸算法學(xué)習(xí)系列之三(快速排序)
-------------------------------------------------------
人老了,腦袋不好用了,偶爾用算法來練練腦子,可以防止早衰。呵呵
??????????????????????????????????????????????????????? jillzhang jillzhang@126.com
總結(jié)
以上是生活随笔為你收集整理的递归算法学习系列之寻找第K大的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C#编程中的66个好习惯 值得收藏
- 下一篇: URAL 1029