2. 二叉堆堆自我調整
3. 二叉堆的**實現
二叉堆:本質上是一種完全二叉樹,它分兩個型別。
什麼是最大堆?
最大堆:最大堆的任何乙個父節點的值,都大於或等於它左、右孩子節點的值。
什麼是最小堆?
最小堆:最小堆的任何乙個父節點的值,都小於或等於它左、右孩子節點的值。
二叉堆的根節點叫作堆頂。最大堆和最小堆堆特點決定了:最大堆的堆頂是整個堆中的最大元素;最小堆的堆頂是整個堆中的最小元素。
對於二叉堆,有如下幾種操作:
這幾種操作都是基於堆的自我調整。所謂堆的自我調整,就是把乙個不符合堆性質的完全二叉樹,調整為乙個堆。以最小堆為例,講解二叉堆事如何進行自我調整的。
插入節點
當二叉堆插入節點時,插入位置是完全二叉樹的最後乙個位置。例如插入乙個新節點,值為0.
此時,新節點的父節點5比0大,顯然不符合最小堆的性質。於是讓新節點**「上浮」**,和父節點交換位置。
繼續用節點0和父節點3做比較,因為0小於3,則讓新節點繼續**「上浮」**。
繼續比較,最終新節點0**「上浮」**,到了堆頂位置。
刪除節點
二叉堆刪除節點的過程和插入節點的過程正好相反,所刪除的是處於堆頂的節點。例如刪除最小堆的堆頂節點1.
此時,為了繼續維持完全二叉樹的結構,我們把堆堆最後乙個節點10臨時不到原本堆頂頂的位置。
接下來,讓暫處堆頂位置的節點10和它的左、右孩子進行比較,如果左、右孩子節點中最小的乙個(顯然是節點2)比節點10小,那麼讓節點10**「下沉」**。
繼續讓節點10和它的左、右孩子做比較,左、右孩子中最小的是節點7,由於10大於7,讓節點10繼續**「下沉」**。
這樣一來,二叉堆重新得到了調整。
構建二叉堆
構建二叉堆,也就是把乙個無序的完全二叉樹調整為二叉堆,本質上就是讓所有非葉子節點依次「下沉」。
下面舉乙個無序完全二叉樹的例子,如下圖所示。
首先,從最後乙個非葉子節點開始,也就是從節點10開始。如果節點10大於它左、右孩子節點中最小的乙個,則節點10」下沉「。
接下來輪到節點3,如果節點3大於它左、右孩子節點中最小的乙個,則節點3「下沉」。
然後輪到節點1,如果節點1大於它左、右孩子節點中最小的乙個,則節點1「下沉」。事實上節點1小於它的左、右孩子,因此不用改變。
接下來輪到節點7,如果節點7大於它左、右孩子節點中最小的乙個,則節點7「下沉」。
節點7繼續比較,繼續「下沉」。
經過上述幾輪比較和「下沉」操作,最終每乙個節點都小於它的左、右孩子節點,乙個無序的完全二叉樹就被構建成了乙個最小堆。
時間複雜度
插入節點:時間複雜度是o(logn);是單一節點的"上浮",平均交換次數都是堆高度的一半。 空間複雜度o(n)
刪除節點:時間複雜度是o(logn);刪除操作是針對單節點的"下沉",平均交換次數都是堆高度的一半。空間複雜度o(n)
二叉堆雖然是乙個完全二叉樹,但它的儲存方式並不是鏈式儲存,而是順序儲存。
因此,二叉堆的所有節點都儲存在陣列中。
在陣列中,在沒有左、右指標的情況下,如何定位乙個父節點的左孩子和右孩子呢?
如上圖所示,採用陣列下標來計算。
假設父節點的下標是parent,那麼它的左孩子下標就是2xparent+1;右孩子下標就是2xparent+2.
示例中,節點6包含9和10兩個孩子節點,節點6在陣列中的下標是3,節點9在陣列中的下標是7,節點10在陣列的下標是8.
7=3x2+1;
8=3x2+2;
**實現
/**
* 「上浮」調整
* param array. 待調整的堆
*/public
static
void
upadjust
(int
array)
array[childindex]
=temp;
}/**
* 「下沉」調整
* param array 待調整的堆
* param parentindex 要「下沉」的父節點
* param length 堆的有效大小
*/public
static
void
downadjust
(int
array,
int parentindex,
int length)
//如果父節點小於任何乙個孩子的值,則直接跳出
if(temp<=array[childindex]
)//無須真正交換,單向賦值即可
array[parentindex]
=array[childindex]
; parentindex=childindex;
childindex=
2*childindex+1;
} array[parentindex]
=temp;
}/**
* 構建堆
* param array 待調整的堆
*/public
static
void
buildheap
(int
array)
}public
static
void
main
(string[
] args)
;upadjust
(array)
; system.out.
println
(arrays.
tostring
(array));
array=
newint
;buildheap
(array)
; system.out.
println
(arrays.
tostring
(array));
}
二叉堆的用處?
二叉堆是實現堆排序以及優先佇列的基礎。
漫畫演算法 學習筆記01
在計算機領域裡,演算法是一系列程式指令,用於處理特定的運算和邏輯問題。衡量演算法優劣的主要標準是時間複雜度和空間複雜度。資料結構是資料的組織 管理和儲存格式,其使用目的是為了高效的訪問和修改資料。資料結構包含陣列 鍊錶這樣的線性資料結構,也包含樹 圖這樣的複雜資料結構。資料結構 data struc...
漫畫演算法 學習筆記(03)
3.實現 4.陣列與鍊錶的比較 鍊錶 linked list 是一種在物理上非連續 非順序的資料結構,由若干節點 node 所組成。private static class node 鍊錶的第乙個節點被稱為頭節點,最後乙個節點被稱為尾節點,尾節點的next指標指向null。對於鍊錶的其中乙個節點a,...
漫畫演算法 學習筆記(23)
q 用兩個棧來模擬乙個佇列,要求實現佇列的兩個基本操作,入隊和出隊。思路 棧的特點是先入後出 filo 出入元素都是在同一端 棧頂 佇列的特點是先入先出 fifo 出入元素是在不同的兩端 隊頭和隊尾 由於我們可以使用兩個棧,那麼可以讓其中乙個棧作為佇列的入口,負責插入新元素 另乙個棧作為佇列的出口,...