二项堆
概述
二项堆是一种可合并堆,由多个二项树组成,支持高效的合并操作。
二项树
二项树Bk的递归定义:
- B0是单节点树
- Bk由两棵Bk-1连接而成,一棵的根作为另一棵的左孩子
| Text Only |
|---|
| B0: ●
B1: ●
|
●
B2: ●
|
●→●
|
●
B3: ●
|
●→●→●
| |
● ●
|
●
|
二项树性质
- Bk有2^k个节点
- Bk的高度为k
- Bk深度d处有C(k,d)个节点
- 根的度数为k
数据结构
| C |
|---|
| typedef struct BinomialTreeNode {
int value;
int degree;
struct BinomialTreeNode *parent;
struct BinomialTreeNode *child;
struct BinomialTreeNode *sibling;
} BinomialTreeNode;
typedef struct {
BinomialTreeNode *head;
} BinomialHeap;
|
创建节点
| C |
|---|
| BinomialTreeNode* createBinomialNode(int value) {
BinomialTreeNode *node = (BinomialTreeNode*)malloc(sizeof(BinomialTreeNode));
node->value = value;
node->degree = 0;
node->parent = NULL;
node->child = NULL;
node->sibling = NULL;
return node;
}
BinomialHeap* createBinomialHeap() {
BinomialHeap *heap = (BinomialHeap*)malloc(sizeof(BinomialHeap));
heap->head = NULL;
return heap;
}
|
合并两棵二项树
| C |
|---|
| BinomialTreeNode* linkBinomialTrees(BinomialTreeNode *t1, BinomialTreeNode *t2) {
if (t1->value > t2->value) {
BinomialTreeNode *temp = t1;
t1 = t2;
t2 = temp;
}
t2->parent = t1;
t2->sibling = t1->child;
t1->child = t2;
t1->degree++;
return t1;
}
|
合并两个堆
| C |
|---|
| BinomialHeap* mergeBinomialHeaps(BinomialHeap *h1, BinomialHeap *h2) {
BinomialHeap *result = createBinomialHeap();
BinomialTreeNode *curr1 = h1->head;
BinomialTreeNode *curr2 = h2->head;
BinomialTreeNode **tail = &result->head;
while (curr1 && curr2) {
if (curr1->degree <= curr2->degree) {
*tail = curr1;
curr1 = curr1->sibling;
} else {
*tail = curr2;
curr2 = curr2->sibling;
}
tail = &((*tail)->sibling);
}
*tail = curr1 ? curr1 : curr2;
return result;
}
BinomialHeap* unionBinomialHeaps(BinomialHeap *h1, BinomialHeap *h2) {
BinomialHeap *heap = mergeBinomialHeaps(h1, h2);
if (heap->head == NULL) return heap;
BinomialTreeNode *prev = NULL;
BinomialTreeNode *curr = heap->head;
BinomialTreeNode *next = curr->sibling;
while (next) {
if (curr->degree != next->degree ||
(next->sibling && next->sibling->degree == curr->degree)) {
prev = curr;
curr = next;
} else {
if (curr->value <= next->value) {
curr->sibling = next->sibling;
linkBinomialTrees(curr, next);
} else {
if (prev == NULL) {
heap->head = next;
} else {
prev->sibling = next;
}
linkBinomialTrees(next, curr);
curr = next;
}
}
next = curr->sibling;
}
return heap;
}
|
插入操作
| C |
|---|
| BinomialHeap* insertBinomialHeap(BinomialHeap *heap, int value) {
BinomialHeap *temp = createBinomialHeap();
temp->head = createBinomialNode(value);
BinomialHeap *result = unionBinomialHeaps(heap, temp);
free(temp);
return result;
}
|
提取最小值
| C |
|---|
| BinomialTreeNode* findMin(BinomialHeap *heap) {
if (heap->head == NULL) return NULL;
BinomialTreeNode *min = heap->head;
BinomialTreeNode *curr = heap->head->sibling;
while (curr) {
if (curr->value < min->value) {
min = curr;
}
curr = curr->sibling;
}
return min;
}
BinomialHeap* reverseList(BinomialTreeNode *node) {
BinomialTreeNode *prev = NULL;
BinomialTreeNode *curr = node;
while (curr) {
BinomialTreeNode *next = curr->sibling;
curr->sibling = prev;
curr->parent = NULL;
prev = curr;
curr = next;
}
BinomialHeap *heap = createBinomialHeap();
heap->head = prev;
return heap;
}
int extractMin(BinomialHeap **heap) {
if ((*heap)->head == NULL) return -1;
BinomialTreeNode *min = (*heap)->head;
BinomialTreeNode *minPrev = NULL;
BinomialTreeNode *curr = (*heap)->head->sibling;
BinomialTreeNode *prev = (*heap)->head;
while (curr) {
if (curr->value < min->value) {
min = curr;
minPrev = prev;
}
prev = curr;
curr = curr->sibling;
}
if (minPrev == NULL) {
(*heap)->head = min->sibling;
} else {
minPrev->sibling = min->sibling;
}
BinomialHeap *childHeap = reverseList(min->child);
*heap = unionBinomialHeaps(*heap, childHeap);
int minValue = min->value;
free(min);
free(childHeap);
return minValue;
}
|
时间复杂度
| 操作 |
时间复杂度 |
| 合并 |
O(log n) |
| 插入 |
O(log n) |
| 获取最小值 |
O(log n) |
| 删除最小值 |
O(log n) |
| 减少键值 |
O(log n) |
| 删除 |
O(log n) |
二项堆 vs 斐波那契堆
| 特性 |
二项堆 |
斐波那契堆 |
| 插入 |
O(log n) |
O(1) 摊还 |
| 删除最小值 |
O(log n) |
O(log n) 摊还 |
| 合并 |
O(log n) |
O(1) 摊还 |
| 实现复杂度 |
中等 |
复杂 |
应用场景
- 可合并优先队列:多队列管理
- 图算法:Dijkstra、Prim优化
- 事件模拟:多事件源合并
- 分布式系统:分布式优先队列
参考资料
- 《算法导论》第19章
- 《数据结构与算法分析》第6章