優先佇列與堆

2021-08-21 17:50:00 字數 3600 閱讀 2206

二 堆

1.1 定義

在很多應用中,我們通常需要按照優先順序情況對待處理物件進行處理,比如首先處理優先順序最高的物件,然後處理次高的物件。最簡單的乙個例子就是,在手機上玩遊戲的時候,如果有來電,那麼系統應該優先處理打進來的**。

在這種情況下,我們的資料結構應該提供兩個最基本的操作,乙個是返回最高優先順序物件,乙個是新增新的物件。這種資料結構就是優先順序佇列(priority queue)

優先順序佇列和通常的棧和佇列一樣,只不過裡面的每乙個元素都有乙個」優先順序」,在處理的時候,首先處理優先順序最高的。如果兩個元素具有相同的優先順序,則按照他們插入到佇列中的先後順序處理。

1.2 api

優先佇列最重要的操作就是刪除最大元素插入元素

刪除最大元素的方法名為delmax(),插入元素的方法名為insert()。定義類 maxpq 的api如下:

類似的,我們會在適當的地方使用另乙個類 minpq。它和 maxpq 類似,只是含有乙個 delmin() 方法來刪除並返回佇列中鍵值最小的那個元素。

1.3 實現

優先順序佇列可以通過陣列,鍊錶,堆或者其他資料結構實現。

最簡單的優先順序佇列可以通過有序、無序陣列來實現,當要獲取最大值的時候,對陣列進行查詢返回即可。

採用普通的陣列或者鍊錶實現,無法使得插入和排序都達到比較好的時間複雜度,在這些初級實現中,插入元素和刪除最大元素這兩個操作之一在最壞情況下需要線性時間來完成 (如表2.4.3所示)。

所以我們需要採用新的資料結構來實現。下面要討論的基於資料結構堆(heap)的實現能夠保證這兩種操作都能更快執行。

資料結構二叉堆能夠很好地實現優先佇列的基本操作。

在二叉堆的陣列中,每個元素都要保證大於等於另兩個特定位置的元素。

2.1 定義

當一棵二叉樹的每個結點都大於等於它的兩個子結點時,它被稱為堆有序

根節點是堆有序的二叉樹中的最大節點。

2.2 表示

可以使用完全二叉樹表示二叉堆(以下簡稱堆),而無需使用指標。

將二叉樹的結點按照層級順序放入陣列中,根節點在位置1(不使用陣列的第乙個位置),它的子節點在位置2和3,子節點的子節點則分別在位置4、5、6、7,以此類推。

從二叉堆中,我們可以得出:

這樣在不使用指標的情況下,也可直接通過計算陣列的索引完成結點的上下移動。

2.3 堆的有序化

用長度為 n+1 的陣列 pq 來表示乙個大小為 n 的堆。

注意:不使用 pq[0],堆元素放在 pq[1] 至 pq[n] 中

堆的有序化:

swim():當某個結點的優先順序上公升(例如在堆底加入乙個新的元素)時,我們需要由下至上恢復堆的順序。

sink():當某個結點的優先順序下降(例如將根節點替換為乙個較小的元素)時,我們需要由上至下恢復堆的順序。

現在就來看這兩種操作。

1、由下至上的堆有序化(上浮)

當乙個結點太大時,它需要 浮(swim)到堆的更高層,直到遇到了乙個更大的父節點。

我們只需要將該元素 k 和其父元素 k/2 進行比較,如果比父元素大,則交換,然後迭代一直到比父元素小為止。

//結點比父節點大,上浮

public

void

swim(int k)

}

2、由上至下的堆有序化(下沉)當乙個結點太小時,它需要 沉(sink)到堆的更低層,直到它的子節點都比它更小或者到達了堆的底部。

我們只需要將該元素 和 它的兩個子節點中的較大者進行比較,如果比較大者小,則交換。

//結點比子節點小,下沉

public

void

sink(int k)

}

2.4 基於堆的優先佇列

swim() 和 sink() 有序化是實現基於堆的優先佇列api的基礎。

優先佇列最重要的操作就是刪除最大元素插入元素

1、插入元素

將新元素加到陣列末尾,並讓這個新元素上浮swim()到合適的位置。

//將n加一併把新元素新增在陣列最後,然後用swim()恢復堆的秩序

public

void

insert(int num)

2、刪除最大元素從陣列頂端刪去最大的元素,並將陣列的最後乙個元素放到頂端,再讓該元素下沉sink()到合適的位置。

//從pq[1]中得到最大元素,然後將pq[n]移動到pq[1],將n減一並用sink()恢復堆的秩序

public

intdelmax()

3、基於堆的優先佇列

對於乙個含有n個元素的基於堆的優先佇列,

插入元素的操作需要不超過 lg

n+1 lgn

+1次比較

刪除最大元素的操作需要不超過 2l

gn2 lg

n次比較

兩種操作都需要在根節點和堆底之間移動元素,而路徑的長度不超過 lgn。對於路徑上的每個節點,刪除最大元素需要兩次比較(除了堆底元素),一次用來找出子節點中的較大者,一次用來確定該子節點是否需要上浮。

堆與優先佇列

分析與思考 陣列是完全二叉樹的儲存結構,完全二叉樹是陣列的邏輯結構,這樣我們就可以使用樹形結構來解決線性問題。堆的插入與刪除 尾部插入,頭部彈出 聯想到了佇列 不同程式語言在實現優先佇列時底層90 是由堆構成的。通過 本身來提高程式設計能力是錯誤的,應注重思維邏輯結構的提公升 資料結構 結構定義 結...

c 堆與優先佇列

以最小堆為例,實現下列操作 向下調整演算法 void down int p heap p a 插入 void insert int a 將p的優先順序上公升為a void increasekey int p,int a 建立堆 void build 例題 poj 2051argus 思路 維持乙個最...

優先佇列《堆》

1.模型 兩個基本操作 insert等價enqueue deletemin刪除最小者 dequeue 2.簡單的實現 1 簡單鍊錶 遍歷刪除min或者排序刪除min 2 使用二叉查詢樹。反覆除去min會使得樹不平衡,並且bst還支援許多不需要的操作。3.二叉堆 優先佇列的實現普遍使用二叉堆,堆有兩個...