首先要明確一點:堆是一種數據結構,而不能算是一種算法,並且堆這種數據結構是基於書這種數據結構的,接下來我將要寫的是堆的向下轉換和向上轉換。

究竟什麼是堆???

堆其實就是一種帶有條件的完全二叉樹,堆分爲兩種:一,最小堆     二,最大堆,當父節點比孩子節點都要小時爲最小堆,當父節點比孩子節點都要大時爲最大堆。

堆有很多用途,並且有時候對效率有非常大的提升,接下來我就以《啊哈算法》中的例子來解析一下堆這種數據結構。

例子:有如下一個樹:


這就是一種最小堆,根據上面我們講的堆得原理,我們可以知道在最小堆中,堆得根節點就是堆中的最小的一個節點,(注意:在一棵二叉樹中 如果父節點時k 則其左孩子是2*k 右節點是2*k+1),如果我們求這些節點中的最小的一個數,並且再插入一個數,我們應該怎麼做呢?

最開始的想法(完全就不往數這方面想),我會把這些節點存到數組中,然後用for循環找到最小值,然後再把最小值刪除,再插入一個新值,這樣的話,時間複雜度就是O(N),其實對於這樣的問題,用堆這種數據結構是比較好的,具體怎麼用呢?

首先我們可以把這樣一個堆(其實就是上圖的樹),存入數組中,數組的第一個元素就是根節點,即最小的節點,(是不是還在等着循環? 哈哈 不用循環最小元素已經找到啦),接下來的問題就是插入一個新元素啦,這一點我們需要注意,因爲爲了下一次這個堆的根節點還是最小節點,我們在插入新的節點後,還是要把這個樹整理成一個堆,這就是重點要講的向下轉換問題。

如圖所示;當我們把根節點取出來,在插入一個新的節點,就像下圖這樣:


我們會發現插入23後,這個樹已經不再是堆了,如果想要變成最小堆,就必須要根據父節點總是比子節點小這個原理把23這個節點向下轉換。

第一步:


和子孩子進行向下轉換!

第二步:


再和右孩子進行轉換!

最後一步:


可以發現,只需要三步,就重新弄成了一個最小堆,這意味着只需要三步,就可以取出兩個最小值,如果用循環,我們需要循環兩個N。

接下來是用代碼實現:

用數組 p[50] 存放這個堆(也就是樹)

void siftdown(int i)
{
int t,flag=0;//t是臨時變量,flag是一個標記。
while(i*2<n&&flag==0)// 如果存在左孩子(因爲是完全二叉樹,所以可能沒有右孩子),並且標記沒有變化,就執行轉換操作
{
if(p[i]>p[i*2])//如果父節點比左孩子大
t=i*2;//把較小的節點的下標給臨時變量
else
t=i;
if(p[t]>p[i*2+1]&&i*2+1<n)//把找到的較小的節點再跟右孩子進行比較
{
t=i*2+1;
}// 上面幾行就是找父節點和兩個孩子節點哪一個最小,把最小節點的下標存入臨時變量
if(t!=i)// 如果所求出的最小節點不是剛開始的節點,就進行交換,如果是剛開始的節點,就說明此節點符合最下堆得原理,就完成了轉換,把標記轉換爲 1 

{
swap(t,i);

i=t;//把轉換的節點進行更新,再進行下一次轉換

}
else
flag=1;

}
}

這就是向下轉換!

還有一種是向上轉換,就是把一個新的節點插入到這顆堆的最後,如果不再是堆,就一步步的向上轉換,使之再次成爲一個堆,這也是在堆中插入新元素的算法。

直接上代碼:

void siftup(int i)
{
if(i==1)//如果此節點就是根節點,就不用調整
return ;
while(i!=1&&flag==0)
{
if(p[i]<p[i/2])// 如果子節點小於父節點,則進行交換
{
t=i/2;
swap(i,t);//此函數要自己實現,交換的不是角標,而是值
i=t;
}
else
{
flag=1;
}
}
}

注意向上轉換和向下轉換的代碼的不同:向下轉換時,需要在父節點和孩子節點中找到一個最小的節點,,因爲如果一個父節點有兩個孩子節點,則轉換的時候需要和較小的子節點進行轉換,而向上轉換時,只需要和父節點比較即可,因爲如果此節點比父節點小,則一定比其兄弟節點小。

接下來就是怎麼建立堆得問題!

一, 

假設有m個頂點

for(int i=1;i<=m;i++)

{

scanf("%d",&p[i]);

siftup(i);

}

二,

先把數存到數組中(其實就是一個樹用數組存起來),然後再對每一個子樹的父節點進行遍歷和調整,直到最後形成一個堆。

代碼如下:

for(int i=n/2;i>=1;i--)//如果一個完全二叉樹樹有n個節點,那麼第一個非葉子節點是n/2

{

siftdown(i);

}

最後還有一個著名的堆排序算法,這個有時間再寫!

此文改編自《啊哈算法》!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章