漫畫演算法 學習筆記(11)

2021-10-20 22:49:32 字數 3361 閱讀 7002

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 出入元素是在不同的兩端 隊頭和隊尾 由於我們可以使用兩個棧,那麼可以讓其中乙個棧作為佇列的入口,負責插入新元素 另乙個棧作為佇列的出口,...