堆也可以說是乙個完全二叉樹,就是除了最底層的,其它層是滿的,既然我們可以用完全二叉樹來表示乙個堆,那麼我們這裡就採用陣列結構的二叉樹來闡述堆的性質。
假設在這裡我們用陣列a表示堆,a[i]表示堆裡面的第i個元素,於是我們通過二叉樹的性質可知:
就如下圖表現所示:
小優化:我們知道在計算機裡面做乘法和除法是特別慢的。但是某些時候,我們就可以採用左移和右移來代替乘以2和除以2的操作,比如1<<2,那麼就是2,4>>1,那麼結果就是2,我們知道左移和右移的操作是非常迅速的。所以我們在計算父節點座標和子節點座標的時候可以採用這種方法來實現:在堆裡面,我們可以大致將堆分為三類#define parent(i) ((i)>>1)
#define leftchild(i) ((i)<<1)
#define rightchild(i) (((i)<<1)+1)
只要在二叉樹結構裡面,對於除了根節點意外的任何節點i都滿足: a[
pare
nt[i
]]i]
那麼就稱具有這種性質的堆為最小堆
與最小堆類似,只要在二叉樹結構裡面,對於除了根節點意外的任何節點i都滿足: a[
pare
nt[i
]]>a[
i]那麼就稱具有這種性質的堆為最大堆
對於即即使最小堆也不是最大堆的堆來說,這種對我們就稱之為堆
假如我們改變最大堆裡面的乙個元素的大小,那麼整個最大堆的性質將會被破壞,這裡我們需要找到一種在改變了最大堆或者是最小堆的元素的情況下,進行一定變換就可以保持堆原有性質的方法!
因為最大堆和最小堆基本類似,於是我們在這裡選出最大堆進行講解,我們假設維護最大堆性質的函式為max-heapify(a,i),這裡輸入需要維護的堆a和改變的元素位置i。在堆a進行維護之前,必須保證i節點的左子樹left(i)和右子樹right(i)有最大堆的性質,這一點很重要
下面我們用偽**實現max-heapify(a,i)
max-heapify(a,i)
if i >= a.heapsize
return
leftchild = leftchild(i)
rightchild = rightchild(i);
maxpos = i
if a[leftchild] > a[i]:
maxpos = leftchild;
if a[rightchild] > a[maxpos]:
maxpos = rightchild;
if(maxpos == i)
return;
exchange(a,maxpos,i)
max-heapify(a,maxpos)在這裡,我們採用將元素沉降的方法,將較小的元素向下沉降,較大的元素向上移動,假設我們這裡有這樣乙個例子:
假設以i為根節點一棵子樹,現在我們要對其從根節點開始進行最大堆的性質維護,那麼我們需要多大的時間花費呢 t(
n)≤t
(n2/
3)+o
(1)
證明:假設我們有一棵完全二叉樹所以按照主定理,我們知道維護堆性質的時間代價為o(t ,這棵二叉樹有
n個節點,高度為h+
1 ,那麼在將根節點去掉以後左子樹剩餘節點數最多為:(2
h+1−
2)/2
+2h=
2∗2h−1(
t 的最底層元素個數為
t為滿二叉樹時最底層元素個數的一半),,在去掉根節點以後,剩下的總結點個數為2h
+1+2
h−1=
3∗2h
−1,那麼在在去掉根節點以後,左子樹的節點數量與及剩下總節點個數相比為2∗
2h−1
3∗2h
−1,於是
limh→∞
2∗2h
−13∗
2h−1
=23
logn
)
堆基礎知識小結
1 chunk 結構 未分配的chunk prev size size p 0 fd bk unused 已分配chunk prev size size p 1 header malloc返回的位址是這裡,注意與未分配的chunk比較,此處應該是fd的起始位置 data 相鄰的chunk prev ...
堆與棧的基礎知識
一 預備知識 程式的記憶體分配 乙個由c c 編譯的程式占用的記憶體分為以下幾個部分 1 棧區 stack 由編譯器自動分配釋放 存放函式的引數值,區域性變數的值等。其操作方式類似於資料結構中的棧。2 堆區 heap 一般由程式設計師分配釋放,若程式設計師不釋放,程式結束時可能由os 注意它與資料結...
優先佇列(堆)基礎知識
優先佇列是一種抽象資料型別,最重要的操作就是刪除最大元素 delmax 和插入元素 insert 二叉堆 能夠很好的實現優先佇列的基本操作 定義 當一顆二叉樹的每個結點都大於等於它的兩個子結點時,它被稱為堆有序。在堆有序的二叉樹中,每個結點都小於等於它的父結點。從任意結點向上,我們都能得到一列非遞減...