雙端堆或是雙端優先隊列 (Double-ended Heap OR double-ended priority queue,DEPQ)
My vault 資料結構筆記:雙端堆或是雙端優先隊列 (Double-ended Heap OR double-ended priority queue,DEPQ)。
✅ 定義規則
-
The root contains no element
-
The left subtree is a Min-Heap
-
The right subtree is a Max-Heap
-
Constraint between the two trees:
-
令 $i$ 為左子樹中的任意節點,$j$ 為右子樹中對應的節點。
-
若 $j$ 不存在(即 $j > n$),則 $j$ 的對應節點為其 父節點。
-
則必須滿足:$i.\text{key} \leq j.\text{key}$
-
[!info] 是一棵 Complete Binary Tree
🧲 對應節點計算公式
左側對應節點(Min‐partner)
給定一個位於 max‐heap 中的節點索引 n(n ≥ 2),對應到 min‐heap 的索引 i:
$$
i = \mathrm{min_partner}(n)
= n ;-; 2^{,\lfloor \log_{2} n\rfloor - 1}.
$$
- 若計算出來的
i超過heap_size,則
$$ i = \Big\lfloor \frac{i}{2} \Big\rfloor. $$
右側對應節點(Max‐partner)
給定一個位於 min‐heap 中的節點索引 n(n ≥ 2),對應到 max‐heap 的父節點索引 j:
$$
j = \mathrm{max_partner}(n)
= i+ 2^{\lfloor \log_2 i \rfloor -1}
\quad(\text{整數除法})
$$
- 若計算出來的
j超過heap_size,則
$$ j = \Big\lfloor \frac{j}{2} \Big\rfloor. $$
Insert X on the DEAP
步驟流程
-
將 x 插入於最後一個節點(即 n+1 位置)
-
分成兩種情況討論:
Case 1:x 位於 Min-Heap(左子樹)
-
找出其在 Max-Heap(右子樹)之對應節點 j
-
判斷:
-
如果 x.key>D[j].keyx.key > D[j].key
D[x] := D[j]; MaxHeapInsert(D, j, x); -
否則:
MinHeapInsert(D, x, x);
-
Case 2:x 位於 Max-Heap(右子樹)
-
找出其在 Min-Heap(左子樹)之對應節點 j
-
判斷:
-
如果 x.key<D[j].keyx.key < D[j].key
D[x] := D[j]; MinHeapInsert(D, j, x); -
否則:
MaxHeapInsert(D, x, x);
-
[!info] 簡單來說 如果今天插入在 max-heap(左子樹)的話就去檢查 min-heap 對應的位置 $i$ 是不是比較大如果比較大就交換執行 Max-Heap 的插入調整,反之亦然
時間複雜度
- $O(\log n)$,主要耗費在 min-heap 或 max-heap 的 insert 操作。
DEAP 插入範例修正:插入 4 與插入 60
✅ 插入 4(x < H[j],插入於 Max-Heap,與 Min-Heap 對應節點交換,進行 MinHeap 調整)
⬇️ 初始結構(插入 4)
o
/ \
5 45
/ \ / \
10 8 25 40
/ \ / \
15 19 20 x(4)
-
插入的節點 4 落在 Max-Heap(右子樹)
-
對應的 Min-Heap 節點為 19
-
因 4 < 19,違反 DEAP 規則(左子樹 ≤ 右子樹)
🔁 執行 swap(將 4 與 19 對調)
o
/ \
5 45
/ \ / \
10 8 25 40
/ \ / \
15 4 20 19
⬆️ 將 4 插入 Min-Heap → MinHeap Insert 調整
ZZ
✅ 插入 60(x > H[j],插入於 Max-Heap,與 Min-Heap 對應節點交換後,進行 MaxHeap 調整)
⬇️ 初始結構(插入 60)
o
/ \
4 45
/ \ / \
5 8 25 40
/ \ / \
15 10 20 19
x(60)
-
插入的節點 60 落在 Max-Heap(右子樹)
-
對應 Min-Heap 的節點為 40
-
因 60 > 40,符合方向,直接插入 MaxHeap
🔁 執行 swap(與 40 對調)
o
/ \
4 60
/ \ / \
5 8 25 45
/ \ / \ \
15 10 20 19 40
⬆️ 將 60 插入 Max-Heap → MaxHeap Insert 調整
- 60 > 45 → 上浮
o
/ \
4 60
/ \ / \
5 8 25 45
/ \ / \ \
15 10 20 19 40
DEAP Delete Min
-
移除最小元素
- 將
D[2](deap 的最小值)取出,留下空缺位置i = 2。
- 將
-
取出最後一個節點
- 將陣列末端節點
x取出並刪除,heap size 減 1。
- 將陣列末端節點
-
填補空缺(在 min-heap 中上移)
while i 有子節點: c = 左右孩子中值較小者 if D[c] < D[i]: D[i] = D[c] i = c else: break -
重插節點
x(DeapInsert)DeapInsert(D, i, x)- 將
x放入空缺的葉節點位置i,再依序做上浮或下沉,以恢復 deap 的雙堆序性。
- 將
範例刪除
(root)
/ \
[ 5 ] [ 70 ]
/ \ / \
[15] [10] [60] [40]
/ \ / \ /
[20][25][30][35][50]
(root)
/ \
[ 10 ] [ 70 ]
/ \ / \
[15] [] [60] [40]
/ \ / \ /
[20][25][30][35][]
(root)
/ \
[ 10 ] [ 70 ]
/ \ / \
[15] [30] [60] [40]
/ \ / \
[20][25] [][35]
(root)
/ \
[ 10 ] [ 70 ]
/ \ / \
[15] [30] [60] [40]
/ \ / \
[20][25] [50][35]
(root)
/ \
[ 10 ] [ 70 ]
/ \ / \
[15] [30] [60] [50]
/ \ / \
[20][25] [40][35]
- 刪除 5 所以, x = 50,然後 5 調整 10 跟 15 比較 所以 10 , 再來空缺是 30 和 35 比較 30 比較小,現在插入 50 在空缺的位置,然後調整 50 對應的位置是 40 所以交換,所以
時間複雜度分析
-
deap-delete-min 無論最後一個節點原本是在 min-heap 還是 max-heap,都能正確運作。
-
由於 deap 的高度為 $O(\log n)$,整體時間複雜度為 $O(\log n)$。