每次插入都是將新資料放在陣列最後。可以發現從這個新資料的父結點到根結點必然為乙個有序的數列,現在的任務是將這個新資料插入到這個有序資料中——這就類似於直接插入排序中將乙個資料併入到有序區間中,對照《白話經典演算法系列之二 直接插入排序的三種實現》不難寫出插入乙個新資料時堆的調整**:
[cpp]view plain
copy
// 新加入i結點 其父結點為(i - 1) / 2
void
minheapfixup(
inta,
inti)
a[i] = temp;
}
[cpp]view plain
copy
//在最小堆中加入新的資料nnum
void
minheapaddnumber(
inta,
intn,
intnnum)
按定義,堆中每次都只能刪除第0個資料。為了便於重建堆,實際的操作是將最後乙個資料的值賦給根結點,然後再從根結點開始進行一次從上向下的調整。調整時先在左右兒子結點中找最小的,如果父結點比這個最小的子結點還**明不需要調整了,反之將父結點和它交換後再考慮後面的結點。相當於從根結點將乙個資料的「下沉」過程。下面給出**:
[cpp]view plain
copy
// 從i節點開始調整,n為節點總數 從0開始計算 i節點的子節點為 2*i+1, 2*i+2
void
minheapfixdown(
inta,
inti,
intn)
a[i] = temp;
} //在最小堆中刪除數
void
minheapdeletenumber(
inta,
intn)
有了堆的插入和刪除後,再考慮下如何對乙個資料進行堆化操作。要乙個乙個的從陣列中取出資料來建立堆吧,不用!先看乙個陣列,如下圖:
很明顯,對葉子結點來說,可以認為它已經是乙個合法的堆了即20,60, 65, 4, 49都分別是乙個合法的堆。只要從a[4]=50開始向下調整就可以了。然後再取a[3]=30,a[2] = 17,a[1] = 12,a[0] = 9分別作一次向下調整操作就可以了。下圖展示了這些步驟:
寫出堆化陣列的**:
[cpp]view plain
copy
//建立最小堆
void
makeminheap(
inta,
intn)
大頂堆小頂堆
堆通常是乙個可以被看做一棵完全二叉樹的陣列物件 如果對一棵有n個結點的完全二叉樹的結點按層序編號 從第1層到第 1層,每層從左到右 則對任一結點i 1 i n 有 1 如果i 1,則結點i無雙親,是二叉樹的根 如果i 1,則其雙親是結點。2 如果2i n,則結點i為葉子結點,無左孩子 否則,其左孩子...
關於堆的判斷 (小頂堆)
l2 3 關於堆的判斷 將一系列給定數字順序插入乙個初始為空的小頂堆h。隨後判斷一系列相關命題是否為真。命題分下列幾種 每組測試第1行包含2個正整數n le 1000 和m le 20 分別是插入元素的個數 以及需要判斷的命題數。下一行給出區間 10000,10000 10000,10000 100...
小頂堆 關於堆的判斷
x is the root x是根結點 x and y are siblings x和y是兄弟結點 x is the parent of y x是y的父結點 x is a child of y x是y的乙個子結點。輸入格式 每組測試第1行包含2個正整數n 1000 和m 20 分別是插入元素的個數 ...