




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
第C#實(shí)現(xiàn)優(yōu)先隊(duì)列和堆排序目錄優(yōu)先隊(duì)列1.API2.初級(jí)實(shí)現(xiàn)3.堆的定義二叉堆表示法4.堆的算法上?。ㄓ上轮辽系亩训挠行蚧┫鲁粒ㄓ缮现料碌亩训挠行蚧└倪M(jìn)堆排序1.堆的構(gòu)造2.下沉排序先下沉后上浮
優(yōu)先隊(duì)列
許多應(yīng)用程序都需要處理有序的元素,但不一定要求它們?nèi)坑行?,或是不一定要一次就將它們排序。很多情況下是收集一些元素,處理當(dāng)前鍵值最大的元素,然后再收集更多的元素,再處理當(dāng)前鍵值最大的元素。這種情況下,需要的數(shù)據(jù)結(jié)構(gòu)支持兩種操作:刪除最大的元素和插入元素。這種數(shù)據(jù)結(jié)構(gòu)類型叫優(yōu)先隊(duì)列。
這里,優(yōu)先隊(duì)列基于二叉堆數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn),用數(shù)組保存元素并按照一定條件排序,以實(shí)現(xiàn)對(duì)數(shù)級(jí)別的刪除和插入操作。
1.API
優(yōu)先隊(duì)列是一種抽象數(shù)據(jù)類型,它表示了一組值和對(duì)這些值的操作,抽象層使應(yīng)用和實(shí)現(xiàn)隔離開來。
2.初級(jí)實(shí)現(xiàn)
1.無序數(shù)組實(shí)現(xiàn)
優(yōu)先隊(duì)列的insert方法和下壓棧的push方法一樣。刪除最大元素時(shí),遍歷數(shù)組找出最大元素,和邊界元素交換。2.有序數(shù)組實(shí)現(xiàn)
插入元素時(shí),將較大的元素向右移一格(和插入排序一樣)。這樣刪除時(shí),就可以直接pop。
使用鏈接也是一樣的邏輯。
這些實(shí)現(xiàn)總有一種操作需要線性級(jí)別的時(shí)間復(fù)雜度。使用二叉堆可以保證操作在對(duì)數(shù)級(jí)別的時(shí)間完成。
3.堆的定義
數(shù)據(jù)結(jié)構(gòu)二叉堆可以很好地實(shí)現(xiàn)優(yōu)先隊(duì)列地基本操作。在二叉堆數(shù)組中,每個(gè)元素都要保證大于等于另兩個(gè)特定位置地元素。同樣,這兩個(gè)位置地元素又至少要大于等于數(shù)組中另外兩個(gè)元素,以此類推。用二叉樹表示:
當(dāng)一棵二叉樹的每個(gè)結(jié)點(diǎn)都大于等于它的兩個(gè)子節(jié)點(diǎn)時(shí),它被成為堆有序。從任意結(jié)點(diǎn)向上,都能得到一列非遞減的元素;從任意結(jié)點(diǎn)向下,都能得到一列非遞增的元素。根結(jié)點(diǎn)是堆有序的二叉樹中最大的結(jié)點(diǎn)。
二叉堆表示法
這里使用完全二叉樹表示:將二叉樹的結(jié)點(diǎn)按照層級(jí)順序(從上到下,從左往右)放入數(shù)組中,不使用數(shù)組的第一個(gè)位置(為了方便計(jì)算),根結(jié)點(diǎn)在位置1,它的子結(jié)點(diǎn)在位置2和3,子結(jié)點(diǎn)的子結(jié)點(diǎn)分別在位置4,5,6,7,一次類推。
在一個(gè)二叉堆中,位置k的結(jié)點(diǎn)的父節(jié)點(diǎn)位置在k/2,而它的兩個(gè)子結(jié)點(diǎn)在2k和2k+1??梢酝ㄟ^計(jì)算數(shù)組的索引而不是指針就可以在樹中上下移動(dòng)。
一棵大小為N的完全二叉樹的高度為lgN。
4.堆的算法
用長度為N+1的私有數(shù)組pq[]表示一個(gè)大小為N的堆。
堆在進(jìn)行插入或刪除操作時(shí),會(huì)打破堆的狀態(tài),需要遍歷堆并按照要求將堆的狀態(tài)恢復(fù)。這個(gè)過程稱為堆的有序化。
堆的有序化分為兩種情況:當(dāng)某個(gè)結(jié)點(diǎn)的優(yōu)先級(jí)上升(或在堆底加入一個(gè)新的元素)時(shí),需要由下至上恢復(fù)堆的順序;當(dāng)某個(gè)結(jié)點(diǎn)的優(yōu)先級(jí)下降(例如將根節(jié)點(diǎn)替換為一個(gè)較小的元素),需要由上至下恢復(fù)堆的順序。
上浮(由下至上的堆的有序化)
當(dāng)某個(gè)結(jié)點(diǎn)比它的父結(jié)點(diǎn)更大時(shí),交換它和它的父節(jié)點(diǎn),這個(gè)結(jié)點(diǎn)交換到它父節(jié)點(diǎn)的位置。但有可能比它現(xiàn)在的父節(jié)點(diǎn)大,需要繼續(xù)上浮,直到遇到比它大的父節(jié)點(diǎn)。(這里不需要比較這個(gè)子結(jié)點(diǎn)和同級(jí)的另一個(gè)子結(jié)點(diǎn),因?yàn)榱硪粋€(gè)子結(jié)點(diǎn)比它們的父結(jié)點(diǎn)?。?/p>
//上浮
privatevoidSwim(intn)
while(n1Less(n/2,n))
Exch(n/2,n);
n=n/2;
}
下沉(由上至下的堆的有序化)
當(dāng)某個(gè)結(jié)點(diǎn)k變得比它的兩個(gè)子結(jié)點(diǎn)(2k和2k+1)更小時(shí),可以通過將它和它的兩個(gè)子結(jié)點(diǎn)較大者交換來恢復(fù)堆有序。交換后在子結(jié)點(diǎn)處可能繼續(xù)打破堆有序,需要繼續(xù)重復(fù)下沉,直到它的子結(jié)點(diǎn)都比它小或到達(dá)底部。
//下沉
privatevoidSink(intk)
while(2*k=N)
intj=2*k;
//取最大的子節(jié)點(diǎn)
if(jNLess(j,j+1))
j++;
//如果父節(jié)點(diǎn)不小子節(jié)點(diǎn),退出循環(huán)
if(!Less(k,j))
break;
//否則交換,繼續(xù)下沉
Exch(j,k);
k=j;
}
知道了上浮和下沉的邏輯,就可以很好理解在二叉堆中插入和刪除元素的邏輯。
插入元素:將新元素加到數(shù)組末尾,增加堆的大小并讓這個(gè)新元素上浮到合適的位置。
刪除最大元素:從數(shù)組頂端(即pq[1])刪除最大元素,并將數(shù)組最后一個(gè)元素放到頂端,減少數(shù)組大小并讓這個(gè)元素下沉到合適位置。
publicclassMaxPriorityQueue
privateIComparable[]pq;
publicintN;
publicMaxPriorityQueue(intmaxN)
pq=newIComparable[maxN+1];
publicboolIsEmpty()
returnN==0;
publicvoidInsert(IComparablevalue)
pq[++N]=value;
Swim(N);
publicIComparableDeleteMax()
IComparablemax=pq[1];
Exch(1,N--);
pq[N+1]=null;
Sink(1);
returnmax;
//下沉
privatevoidSink(intk)
while(2*k=N)
intj=2*k;
//取最大的子節(jié)點(diǎn)
if(jNLess(j,j+1))
j++;
//如果父節(jié)點(diǎn)不小子節(jié)點(diǎn),退出循環(huán)
if(!Less(k,j))
break;
//否則交換,繼續(xù)下沉
Exch(j,k);
k=j;
//上浮
privatevoidSwim(intn)
while(n1Less(n/2,n))
Exch(n/2,n);
n=n/2;
privatevoidExch(inti,intj)
IComparabletemp=pq[i];
pq[i]=pq[j];
pq[j]=temp;
privateboolLess(inti,intj)
returnpq[i].CompareTo(pq[j])
}
上述算法對(duì)優(yōu)先隊(duì)列的實(shí)現(xiàn)能夠保證插入和刪除最大元素這兩個(gè)操作的用時(shí)和隊(duì)列的大小成對(duì)數(shù)關(guān)系。這里省略了動(dòng)態(tài)調(diào)整數(shù)組大小的代碼,可以參考下壓棧。
對(duì)于一個(gè)含有N個(gè)元素的基于堆的優(yōu)先隊(duì)列,插入元素操作只需要不超過(lgN+1)次比較,因?yàn)镹可能不是2的冪。刪除最大元素的操作需要不超過2lgN次比較(兩個(gè)子結(jié)點(diǎn)的比較和父結(jié)點(diǎn)與較大子節(jié)點(diǎn)的比較)。
對(duì)于需要大量混雜插入和刪除最大元素的操作,優(yōu)先隊(duì)列很適合。
改進(jìn)
1.多叉堆
基于數(shù)組表示的完全三叉樹:對(duì)于數(shù)組1至N的N個(gè)元素,位置k的結(jié)點(diǎn)大于等于位于3k-1,3k,3k+1的結(jié)點(diǎn),小于等于位于(k+1)/3的結(jié)點(diǎn)。2.調(diào)整數(shù)組大小
使用動(dòng)態(tài)數(shù)組,可以構(gòu)造一個(gè)無需關(guān)注隊(duì)列大小的優(yōu)先隊(duì)列??梢詤⒖枷聣簵!?.索引優(yōu)先隊(duì)列
在許多應(yīng)用程序中,允許客戶端引用優(yōu)先級(jí)隊(duì)列中已經(jīng)存在的項(xiàng)目是有意義的。一種簡單的方法是將唯一的整數(shù)索引與每個(gè)項(xiàng)目相關(guān)聯(lián)。
堆排序
我們可以把任意優(yōu)先隊(duì)列變成一種排序方法:先將所有元素插入一個(gè)查找最小元素的優(yōu)先隊(duì)列,再重復(fù)調(diào)用刪除操作刪除最小元素來將它們按順序刪除。這種排序成為堆排序。
堆排序的第一步是堆的構(gòu)造,第二步是下沉排序階段。
1.堆的構(gòu)造
簡單的方法是利用前面優(yōu)先隊(duì)列插入元素的方法,從左到右遍歷數(shù)組調(diào)用Swim方法(由上算法所需時(shí)間和NlogN成正比)。一個(gè)更聰明高效的方法是,從右(中間位置)到左調(diào)用Sink方法,只需遍歷一半數(shù)組,因?yàn)榱硪话胧谴笮?的堆。這種方法只需少于2N次比較和少于N次交換。(堆的構(gòu)造過程中處理的堆都比較小。例如,要構(gòu)造一個(gè)127個(gè)元素的數(shù)組,需要處理32個(gè)大小為3的堆,16個(gè)大小為7的堆,8個(gè)大小為15的堆,4個(gè)大小為31的堆,2個(gè)大小為63的堆和1個(gè)大小為127的堆,因此在最壞情況下,需要32*1+16*2+8*3+4*4+2*5+1*6=120次交換,以及兩倍的比較)。
2.下沉排序
堆排序的主要工作在第二階段。將堆中最大元素和堆底元素交換,并下沉至N--。相當(dāng)于刪除最大元素并將堆底元素放至堆頂(優(yōu)先隊(duì)列刪除操作),將刪除的最大元素放入空出的數(shù)組位置。
publicclassMaxPriorityQueueSort
publicstaticvoidSort(IComparable[]pq)
intn=pq.Length;
for(vark=n/2;kk--)
Sink(pq,k,n);
//上浮需要遍歷全部
//for(vark=n;kk--)
//Swim(pq,k);
while(n1)
Exch(pq,1,n--);
Sink(pq,1,n);
privatestaticvoidSwim(IComparable[]pq,intn)
while(n1Less(pq,n/2,n))
Exch(pq,n/2,n);
n=n/2;
//下沉
privatestaticvoidSink(IComparable[]pq,intk,intN)
while(2*k=N)
intj=2*k;
//取最大的子節(jié)點(diǎn)
if(jNLess(pq,j,j+1))
j++;
//如果父節(jié)點(diǎn)不小子節(jié)點(diǎn),退出循環(huán)
if(!Less(pq,k,j))
break;
//否則交換,繼續(xù)下沉
Exch(pq,j,k);
k=j;
privatestaticvoidExch(IComparable[]pq,inti,intj)
IComparabletemp=pq[i-1];
pq[i-1]=pq[j-1];
pq[j-1]=temp;
privatestaticboolLess(IComparable[]pq,inti,intj)
returnpq[i-1].CompareTo(pq[j-1])
publicstaticvoidShow(IComparable[]a)
for(vari=0;ia.Length;i++)
Console.WriteLine(a[i]);
}
堆排序的軌跡
將N個(gè)元素排序,堆排序只需少于(2NlgN+2N)次比較以及一半次數(shù)的交換。2N來自堆的構(gòu)造,2NlgN是每次下沉操作最多需要2lgN次比較。
先下沉后上浮
在排序過程中,大多數(shù)重新插入堆中的項(xiàng)目都會(huì)一直到達(dá)底部。因此,通過避免檢查元素是否已到達(dá)其位置,可以簡單地提升兩個(gè)子結(jié)點(diǎn)中的較大者直到到達(dá)底部,然后上浮到適當(dāng)位置,從
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 過繼協(xié)議書范本
- 輻射貼模具合同協(xié)議
- 還款貸款協(xié)議書范本
- 普查保密協(xié)議書
- 退林還耕協(xié)議合同書范本
- 車車輛銷售合同協(xié)議
- 星星獎(jiǎng)勵(lì)協(xié)議書
- 死者債權(quán)協(xié)議書
- 遺贈(zèng)扶養(yǎng)協(xié)議書合同
- 遠(yuǎn)程雇用協(xié)議性合同
- 消防救援-消防火場供水
- 違反公務(wù)用車管理制度談心談話記錄內(nèi)容
- 地鐵防淹門系統(tǒng)的方案比選和設(shè)計(jì)
- 辦理證件協(xié)議書
- PAC(流產(chǎn)后關(guān)愛)項(xiàng)目之流產(chǎn)與避孕培訓(xùn)課件
- 山西煤炭運(yùn)銷集團(tuán)三元石窟煤業(yè)有限公司礦山礦產(chǎn)資源開發(fā)利用、地質(zhì)環(huán)境保護(hù)與土地復(fù)墾方案
- 團(tuán)隊(duì)項(xiàng)目任務(wù)完成進(jìn)度跟進(jìn)表模板
- 山東省應(yīng)急管理普法知識(shí)競賽參考題庫-中(多選題)
- 聶耳音樂課件人物介紹
- 2023年教師基本功市級(jí)考核初中物理試卷
- PPAP項(xiàng)目計(jì)劃表模板
評(píng)論
0/150
提交評(píng)論