6-3 斐波那契堆
斐波那契堆(Fibonacci Heap)
斐波那契堆是一种可合并堆,由一组最小堆有序的树组成。它的核心思想是"延迟合并"(lazy consolidation)——插入时只把节点加入根链表,不做任何整理,直到提取最小值时才统一合并相同度数的树。这使得插入、减小键值、合并操作的摊还时间均为 O(1)。
之所以叫"斐波那契堆",是因为堆中树的大小与斐波那契数列相关,这个关系保证了 extractMin 的摊还复杂度为 O(log n)。
斐波那契堆的结构:
- 所有树的根通过循环双向链表(circular doubly linked list)连接。
- 每个节点的子节点也通过循环双向链表连接。
- 维护一个
min指针指向最小键值的根节点。 - 节点有
marked标记:如果一个非根节点失去了子节点(不是因为 extractMin),就标记它。
min → [3] ⇄ [7] ⇄ [5] ⇄ (back to [3]) ← 根链表(循环双向)
| |
[8] [10] ⇄ [12] ← 子链表
|
[15]
节点定义
C++ 实现
struct FibNode
{
int key;
int degree; // number of children
bool marked; // whether node has lost a child
FibNode *parent;
FibNode *child; // any one child
FibNode *left; // circular list siblings
FibNode *right;
FibNode(int k) : key(k), degree(0), marked(false),
parent(nullptr), child(nullptr)
{
left = right = this; // point to self
}
};
C 实现
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <limits.h>
typedef struct FibNode
{
int key;
int degree;
bool marked;
struct FibNode *parent;
struct FibNode *child;
struct FibNode *left;
struct FibNode *right;
} FibNode;
FibNode* createFibNode(int key)
{
FibNode* node = (FibNode*)malloc(sizeof(FibNode));
node->key = key;
node->degree = 0;
node->marked = false;
node->parent = NULL;
node->child = NULL;
node->left = node;
node->right = node;
return node;
}
Python 实现
class FibNode:
def __init__(self, key):
self.key = key
self.degree = 0
self.marked = False
self.parent = None
self.child = None
self.left = self # circular list
self.right = self
Go 实现
type FibNode struct {
Key int
Degree int
Marked bool
Parent *FibNode
Child *FibNode
Left *FibNode
Right *FibNode
}
func newFibNode(key int) *FibNode {
node := &FibNode{
Key: key,
Degree: 0,
Marked: false,
Parent: nil,
Child: nil,
}
node.Left = node // circular list
node.Right = node
return node
}
节点使用循环双向链表连接兄弟节点,Left 和 Right 初始化时指向自身。Degree 记录子节点数量,Marked 标记该节点是否失去过子节点。
斐波那契堆的结构定义
C++ 实现
class FibonacciHeap
{
private:
FibNode* minNode;
int nodeCount;
// add node to circular doubly linked list
void addToRootList(FibNode* node)
{
if (minNode == nullptr)
{
minNode = node;
node->left = node->right = node;
}
else
{
node->right = minNode->right;
node->left = minNode;
minNode->right->left = node;
minNode->right = node;
}
}
// remove node from its circular list
void removeFromList(FibNode* node)
{
node->left->right = node->right;
node->right->left = node->left;
}
// link tree y under x (y becomes child of x)
void link(FibNode* y, FibNode* x)
{
removeFromList(y);
y->parent = x;
if (x->child == nullptr)
{
x->child = y;
y->left = y->right = y;
}
else
{
y->right = x->child->right;
y->left = x->child;
x->child->right->left = y;
x->child->right = y;
}
x->degree++;
y->marked = false;
}
// consolidate trees after extractMin
void consolidate();
// cut node from parent, add to root list
void cut(FibNode* x, FibNode* y)
{
// remove x from y's child list
if (y->child == x)
{
if (x->right == x)
{
y->child = nullptr;
}
else
{
y->child = x->right;
}
}
removeFromList(x);
y->degree--;
// add x to root list
addToRootList(x);
x->parent = nullptr;
x->marked = false;
}
void cascadeCut(FibNode* node)
{
FibNode* p = node->parent;
if (p != nullptr)
{
if (!node->marked)
{
node->marked = true;
}
else
{
cut(node, p);
cascadeCut(p);
}
}
}
public:
FibonacciHeap() : minNode(nullptr), nodeCount(0) {}
void insert(int key);
int findMin();
int extractMin();
void decreaseKey(FibNode* node, int newKey);
static FibonacciHeap merge(FibonacciHeap& h1, FibonacciHeap& h2);
bool isEmpty() { return minNode == nullptr; }
};
C 实现
typedef struct FibonacciHeap
{
FibNode* minNode;
int nodeCount;
} FibonacciHeap;
FibonacciHeap* createFibHeap()
{
FibonacciHeap* heap = (FibonacciHeap*)malloc(sizeof(FibonacciHeap));
heap->minNode = NULL;
heap->nodeCount = 0;
return heap;
}
Python 实现
class FibonacciHeap:
def __init__(self):
self.min_node = None
self.node_count = 0
def is_empty(self):
return self.min_node is None
def _add_to_root_list(self, node):
if self.min_node is None:
self.min_node = node
node.left = node.right = node
else:
node.right = self.min_node.right
node.left = self.min_node
self.min_node.right.left = node
self.min_node.right = node
def _remove_from_list(self, node):
node.left.right = node.right
node.right.left = node.left
def _link(self, y, x):
"""Link tree y under x (y becomes child of x)."""
self._remove_from_list(y)
y.parent = x
if x.child is None:
x.child = y
y.left = y.right = y
else:
y.right = x.child.right
y.left = x.child
x.child.right.left = y
x.child.right = y
x.degree += 1
y.marked = False
Go 实现
type FibHeap struct {
Min *FibNode
Count int
}
func newFibHeap() *FibHeap {
return &FibHeap{Min: nil, Count: 0}
}
func (h *FibHeap) isEmpty() bool {
return h.Min == nil
}
// addToRootList 将节点加入根链表(循环双向链表)
func (h *FibHeap) addToRootList(node *FibNode) {
if h.Min == nil {
h.Min = node
node.Left = node
node.Right = node
} else {
node.Right = h.Min.Right
node.Left = h.Min
h.Min.Right.Left = node
h.Min.Right = node
}
}
// removeFromList 将节点从其所在循环链表中移除
func removeFromList(node *FibNode) {
node.Left.Right = node.Right
node.Right.Left = node.Left
}
// link 将树 y 链接到 x 下面(y 成为 x 的子节点)
func (h *FibHeap) link(y, x *FibNode) {
removeFromList(y)
y.Parent = x
if x.Child == nil {
x.Child = y
y.Left = y
y.Right = y
} else {
y.Right = x.Child.Right
y.Left = x.Child
x.Child.Right.Left = y
x.Child.Right = y
}
x.Degree++
y.Marked = false
}
FibHeap 维护一个 Min 指针指向根链表中的最小节点。addToRootList 和 removeFromList 操作循环双向链表,link 将一棵树链接为另一棵树的子树并增加度数。
插入操作
插入操作非常简单:创建一个单节点,加入根链表,更新 min 指针。实际时间 O(1)。
C++ 实现
void FibonacciHeap::insert(int key)
{
FibNode* node = new FibNode(key);
addToRootList(node);
if (minNode == nullptr || node->key < minNode->key)
{
minNode = node;
}
nodeCount++;
}
C 实现
void fibInsert(FibonacciHeap* heap, int key)
{
FibNode* node = createFibNode(key);
if (heap->minNode == NULL)
{
heap->minNode = node;
}
else
{
// add to root list
node->right = heap->minNode->right;
node->left = heap->minNode;
heap->minNode->right->left = node;
heap->minNode->right = node;
if (key < heap->minNode->key)
{
heap->minNode = node;
}
}
heap->nodeCount++;
}
Python 实现
def insert(self, key):
node = FibNode(key)
self._add_to_root_list(node)
if self.min_node is None or node.key < self.min_node.key:
self.min_node = node
self.node_count += 1
Go 实现
func (h *FibHeap) insert(key int) {
node := newFibNode(key)
h.addToRootList(node)
if h.Min == nil || node.Key < h.Min.Key {
h.Min = node
}
h.Count++
}
插入时创建新节点并加入根链表,如果新节点键值更小则更新 Min 指针。操作实际时间 O(1)。
查找最小值
直接返回 min 指针指向的节点。O(1)。
C++ 实现
int FibonacciHeap::findMin()
{
if (minNode == nullptr)
{
std::cout << "Heap is empty\n";
return -1;
}
return minNode->key;
}
C 实现
int fibFindMin(FibonacciHeap* heap)
{
if (heap->minNode == NULL)
{
printf("Heap is empty\n");
return -1;
}
return heap->minNode->key;
}
Python 实现
def find_min(self):
if self.min_node is None:
print("Heap is empty")
return None
return self.min_node.key
Go 实现
func (h *FibHeap) findMin() (int, bool) {
if h.Min == nil {
fmt.Println("Heap is empty")
return 0, false
}
return h.Min.Key, true
}
直接返回 Min 指针指向节点的键值。第二个返回值 bool 表示堆是否为空。O(1) 时间。
合并操作(Union)
将两个斐波那契堆的根链表拼接在一起,更新 min 指针。O(1) 实际时间,不需要任何树的重构。
C++ 实现
FibonacciHeap FibonacciHeap::merge(FibonacciHeap& h1, FibonacciHeap& h2)
{
FibonacciHeap result;
if (h1.minNode == nullptr)
{
result.minNode = h2.minNode;
}
else if (h2.minNode == nullptr)
{
result.minNode = h1.minNode;
}
else
{
// concatenate root lists
FibNode* h1Right = h1.minNode->right;
FibNode* h2Right = h2.minNode->right;
h1.minNode->right = h2Right;
h2Right->left = h1.minNode;
h2.minNode->right = h1Right;
h1Right->left = h2.minNode;
// set min
if (h1.minNode->key < h2.minNode->key)
{
result.minNode = h1.minNode;
}
else
{
result.minNode = h2.minNode;
}
}
result.nodeCount = h1.nodeCount + h2.nodeCount;
return result;
}
Python 实现
@staticmethod
def merge(h1, h2):
result = FibonacciHeap()
if h1.min_node is None:
result.min_node = h2.min_node
elif h2.min_node is None:
result.min_node = h1.min_node
else:
# concatenate root lists
h1_right = h1.min_node.right
h2_right = h2.min_node.right
h1.min_node.right = h2_right
h2_right.left = h1.min_node
h2.min_node.right = h1_right
h1_right.left = h2.min_node
if h1.min_node.key < h2.min_node.key:
result.min_node = h1.min_node
else:
result.min_node = h2.min_node
result.node_count = h1.node_count + h2.node_count
return result
Go 实现
func merge(h1, h2 *FibHeap) *FibHeap {
result := newFibHeap()
if h1.Min == nil {
result.Min = h2.Min
} else if h2.Min == nil {
result.Min = h1.Min
} else {
// 拼接两个根链表
h1Right := h1.Min.Right
h2Right := h2.Min.Right
h1.Min.Right = h2Right
h2Right.Left = h1.Min
h2.Min.Right = h1Right
h1Right.Left = h2.Min
// 设置新的 Min 指针
if h1.Min.Key < h2.Min.Key {
result.Min = h1.Min
} else {
result.Min = h2.Min
}
}
result.Count = h1.Count + h2.Count
return result
}
合并操作通过拼接两个堆的根链表实现,无需重构任何树。更新 Min 指针为两个堆中较小者。O(1) 实际时间。
提取最小值(Extract Min)
这是最复杂的操作。步骤:
- 将 min 节点的所有子节点加入根链表。
- 从根链表中移除 min 节点。
- 合并(Consolidate):将根链表中所有度数相同的树合并,直到没有两棵树度数相同。
- 更新 min 指针。
合并过程类似二项式队列,摊还时间 O(log n)。
C++ 实现
void FibonacciHeap::consolidate()
{
// max degree <= log2(n), we use 2*log2(n)+1 as upper bound
int maxDegree = 1;
int temp = nodeCount;
while (temp > 1) { temp >>= 1; maxDegree++; }
std::vector<FibNode*> degreeTable(maxDegree + 1, nullptr);
// collect all root nodes
std::vector<FibNode*> roots;
FibNode* current = minNode;
if (current != nullptr)
{
roots.push_back(current);
current = current->right;
while (current != minNode)
{
roots.push_back(current);
current = current->right;
}
}
for (FibNode* root : roots)
{
FibNode* x = root;
int d = x->degree;
while (degreeTable[d] != nullptr)
{
FibNode* y = degreeTable[d];
// ensure x has smaller key
if (x->key > y->key)
{
FibNode* temp = x;
x = y;
y = temp;
}
link(y, x);
degreeTable[d] = nullptr;
d++;
}
degreeTable[d] = x;
}
// rebuild root list and find new min
minNode = nullptr;
for (FibNode* node : degreeTable)
{
if (node != nullptr)
{
node->left = node->right = node;
if (minNode == nullptr)
{
minNode = node;
}
else
{
addToRootList(node);
if (node->key < minNode->key)
{
minNode = node;
}
}
}
}
}
int FibonacciHeap::extractMin()
{
FibNode* z = minNode;
if (z == nullptr)
{
std::cout << "Heap is empty\n";
return -1;
}
// add children to root list
if (z->child != nullptr)
{
FibNode* child = z->child;
FibNode* start = child;
do
{
FibNode* next = child->right;
addToRootList(child);
child->parent = nullptr;
child = next;
} while (child != start);
}
// remove z from root list
removeFromList(z);
if (z == z->right)
{
minNode = nullptr;
}
else
{
minNode = z->right;
consolidate();
}
nodeCount--;
int minKey = z->key;
delete z;
return minKey;
}
C 实现
void fibConsolidate(FibonacciHeap* heap)
{
int maxDegree = 1;
int temp = heap->nodeCount;
while (temp > 1) { temp >>= 1; maxDegree++; }
FibNode** degreeTable = (FibNode**)calloc(maxDegree + 1, sizeof(FibNode*));
// collect roots
FibNode* roots[128];
int rootCount = 0;
if (heap->minNode != NULL)
{
FibNode* cur = heap->minNode;
roots[rootCount++] = cur;
cur = cur->right;
while (cur != heap->minNode)
{
roots[rootCount++] = cur;
cur = cur->right;
}
}
for (int i = 0; i < rootCount; i++)
{
FibNode* x = roots[i];
int d = x->degree;
while (degreeTable[d] != NULL)
{
FibNode* y = degreeTable[d];
if (x->key > y->key)
{
FibNode* t = x; x = y; y = t;
}
// link y under x
y->left->right = y->right;
y->right->left = y->left;
y->parent = x;
if (x->child == NULL)
{
x->child = y;
y->left = y->right = y;
}
else
{
y->right = x->child->right;
y->left = x->child;
x->child->right->left = y;
x->child->right = y;
}
x->degree++;
y->marked = false;
degreeTable[d] = NULL;
d++;
}
degreeTable[d] = x;
}
heap->minNode = NULL;
for (int i = 0; i <= maxDegree; i++)
{
if (degreeTable[i] != NULL)
{
degreeTable[i]->left = degreeTable[i]->right = degreeTable[i];
if (heap->minNode == NULL)
{
heap->minNode = degreeTable[i];
}
else
{
// add to root list
degreeTable[i]->right = heap->minNode->right;
degreeTable[i]->left = heap->minNode;
heap->minNode->right->left = degreeTable[i];
heap->minNode->right = degreeTable[i];
if (degreeTable[i]->key < heap->minNode->key)
{
heap->minNode = degreeTable[i];
}
}
}
}
free(degreeTable);
}
int fibExtractMin(FibonacciHeap* heap)
{
FibNode* z = heap->minNode;
if (z == NULL)
{
printf("Heap is empty\n");
return -1;
}
// add children to root list
if (z->child != NULL)
{
FibNode* child = z->child;
FibNode* start = child;
do
{
FibNode* next = child->right;
child->right = heap->minNode->right;
child->left = heap->minNode;
heap->minNode->right->left = child;
heap->minNode->right = child;
child->parent = NULL;
child = next;
} while (child != start);
}
// remove z from list
z->left->right = z->right;
z->right->left = z->left;
if (z == z->right)
{
heap->minNode = NULL;
}
else
{
heap->minNode = z->right;
fibConsolidate(heap);
}
heap->nodeCount--;
int minKey = z->key;
free(z);
return minKey;
}
Python 实现
def _consolidate(self):
import math
max_degree = int(math.log2(self.node_count)) + 2 if self.node_count > 0 else 1
degree_table = [None] * (max_degree + 1)
# collect all root nodes
roots = []
if self.min_node is not None:
roots.append(self.min_node)
current = self.min_node.right
while current != self.min_node:
roots.append(current)
current = current.right
for root in roots:
x = root
d = x.degree
while degree_table[d] is not None:
y = degree_table[d]
if x.key > y.key:
x, y = y, x
self._link(y, x)
degree_table[d] = None
d += 1
degree_table[d] = x
# rebuild root list and find new min
self.min_node = None
for node in degree_table:
if node is not None:
node.left = node.right = node
if self.min_node is None:
self.min_node = node
else:
self._add_to_root_list(node)
if node.key < self.min_node.key:
self.min_node = node
def extract_min(self):
z = self.min_node
if z is None:
print("Heap is empty")
return None
# add children to root list
if z.child is not None:
child = z.child
start = child
while True:
next_child = child.right
self._add_to_root_list(child)
child.parent = None
if child == start:
break
child = next_child
# remove z from root list
self._remove_from_list(z)
if z == z.right:
self.min_node = None
else:
self.min_node = z.right
self._consolidate()
self.node_count -= 1
return z.key
Go 实现
func (h *FibHeap) consolidate() {
maxDeg := int(math.Log2(float64(h.Count))) + 2
table := make([]*FibNode, maxDeg+1)
// 收集所有根节点
var roots []*FibNode
if h.Min != nil {
roots = append(roots, h.Min)
cur := h.Min.Right
for cur != h.Min {
roots = append(roots, cur)
cur = cur.Right
}
}
for _, r := range roots {
x := r
d := x.Degree
for d < len(table) && table[d] != nil {
y := table[d]
// 确保 x 的键值更小
if x.Key > y.Key {
x, y = y, x
}
h.link(y, x)
table[d] = nil
d++
}
// 扩展 table 如果需要
for d >= len(table) {
table = append(table, nil)
}
table[d] = x
}
// 重建根链表并找到新的 Min
h.Min = nil
for _, n := range table {
if n != nil {
n.Left = n
n.Right = n
if h.Min == nil {
h.Min = n
} else {
h.addToRootList(n)
if n.Key < h.Min.Key {
h.Min = n
}
}
}
}
}
func (h *FibHeap) extractMin() (int, bool) {
z := h.Min
if z == nil {
fmt.Println("Heap is empty")
return 0, false
}
// 将 min 节点的所有子节点加入根链表
if z.Child != nil {
child := z.Child
start := child
for {
next := child.Right
h.addToRootList(child)
child.Parent = nil
if child == start {
break
}
child = next
}
}
// 从根链表中移除 z
removeFromList(z)
if z == z.Right {
h.Min = nil
} else {
h.Min = z.Right
h.consolidate()
}
h.Count--
return z.Key, true
}
consolidate 使用度数表合并相同度数的树,直到没有两棵树度数相同。extractMin 先将 min 的子节点提升到根链表,移除 min 后调用 consolidate 整理。摊还 O(log n)。
减小键值(Decrease Key)
将某个节点的键值减小后,如果破坏了堆性质(新键值小于父节点),就执行:
- 剪切(Cut):将该节点从父节点剪下,加入根链表。
- 级联剪切(Cascade Cut):如果父节点已被标记,则也剪下父节点,递归向上。
这个操作是斐波那契堆的核心优势之一:摊还 O(1)。
C++ 实现
void FibonacciHeap::decreaseKey(FibNode* node, int newKey)
{
if (newKey > node->key)
{
std::cout << "New key is greater than current key\n";
return;
}
node->key = newKey;
FibNode* parent = node->parent;
if (parent != nullptr && node->key < parent->key)
{
cut(node, parent);
cascadeCut(parent);
}
if (node->key < minNode->key)
{
minNode = node;
}
}
C 实现
void fibCut(FibonacciHeap* heap, FibNode* x, FibNode* y)
{
// remove x from y's child list
if (y->child == x)
{
if (x->right == x)
{
y->child = NULL;
}
else
{
y->child = x->right;
}
}
x->left->right = x->right;
x->right->left = x->left;
y->degree--;
// add x to root list
x->right = heap->minNode->right;
x->left = heap->minNode;
heap->minNode->right->left = x;
heap->minNode->right = x;
x->parent = NULL;
x->marked = false;
}
void fibCascadeCut(FibonacciHeap* heap, FibNode* node)
{
FibNode* p = node->parent;
if (p != NULL)
{
if (!node->marked)
{
node->marked = true;
}
else
{
fibCut(heap, node, p);
fibCascadeCut(heap, p);
}
}
}
void fibDecreaseKey(FibonacciHeap* heap, FibNode* node, int newKey)
{
if (newKey > node->key)
{
printf("New key is greater than current key\n");
return;
}
node->key = newKey;
FibNode* parent = node->parent;
if (parent != NULL && node->key < parent->key)
{
fibCut(heap, node, parent);
fibCascadeCut(heap, parent);
}
if (node->key < heap->minNode->key)
{
heap->minNode = node;
}
}
Python 实现
def _cut(self, x, y):
"""Cut x from parent y, add x to root list."""
# remove x from y's child list
if y.child == x:
if x.right == x:
y.child = None
else:
y.child = x.right
self._remove_from_list(x)
y.degree -= 1
self._add_to_root_list(x)
x.parent = None
x.marked = False
def _cascade_cut(self, node):
p = node.parent
if p is not None:
if not node.marked:
node.marked = True
else:
self._cut(node, p)
self._cascade_cut(p)
def decrease_key(self, node, new_key):
if new_key > node.key:
print("New key is greater than current key")
return
node.key = new_key
parent = node.parent
if parent is not None and node.key < parent.key:
self._cut(node, parent)
self._cascade_cut(parent)
if node.key < self.min_node.key:
self.min_node = node
Go 实现
// cut 将节点 x 从父节点 y 剪下,加入根链表
func (h *FibHeap) cut(x, y *FibNode) {
// 从 y 的子链表中移除 x
if y.Child == x {
if x.Right == x {
y.Child = nil
} else {
y.Child = x.Right
}
}
removeFromList(x)
y.Degree--
h.addToRootList(x)
x.Parent = nil
x.Marked = false
}
// cascadeCut 级联剪切:如果父节点已标记,递归向上剪切
func (h *FibHeap) cascadeCut(node *FibNode) {
p := node.Parent
if p != nil {
if !node.Marked {
node.Marked = true
} else {
h.cut(node, p)
h.cascadeCut(p)
}
}
}
func (h *FibHeap) decreaseKey(node *FibNode, newKey int) {
if newKey > node.Key {
fmt.Println("New key is greater than current key")
return
}
node.Key = newKey
parent := node.Parent
if parent != nil && node.Key < parent.Key {
h.cut(node, parent)
h.cascadeCut(parent)
}
if node.Key < h.Min.Key {
h.Min = node
}
}
decreaseKey 减小键值后,如果破坏了堆性质就执行剪切和级联剪切。cut 将节点移至根链表并清除标记,cascadeCut 递归处理已标记的祖先节点。摊还 O(1)。
删除操作
删除一个节点:先将键值减小到极小值(使其成为新的 min),然后执行 extractMin。摊还 O(log n)。
C++ 实现
void deleteNode(FibNode* node)
{
decreaseKey(node, INT_MIN);
extractMin();
}
C 实现
void fibDelete(FibonacciHeap* heap, FibNode* node)
{
fibDecreaseKey(heap, node, INT_MIN);
fibExtractMin(heap);
}
Python 实现
def delete(self, node):
self.decrease_key(node, float('-inf'))
self.extract_min()
Go 实现
func (h *FibHeap) delete(node *FibNode) {
h.decreaseKey(node, math.MinInt)
h.extractMin()
}
删除操作通过将键值减小到 math.MinInt(使其成为最小节点),然后调用 extractMin 将其移除。摊还 O(log n)。
完整实现
C++ 完整实现
#include <iostream>
#include <vector>
#include <cmath>
#include <climits>
struct FibNode
{
int key;
int degree;
bool marked;
FibNode *parent, *child, *left, *right;
FibNode(int k) : key(k), degree(0), marked(false),
parent(nullptr), child(nullptr)
{
left = right = this;
}
};
class FibonacciHeap
{
private:
FibNode* minNode;
int nodeCount;
void addToRootList(FibNode* node)
{
if (!minNode)
{
minNode = node;
node->left = node->right = node;
}
else
{
node->right = minNode->right;
node->left = minNode;
minNode->right->left = node;
minNode->right = node;
}
}
void removeFromList(FibNode* node)
{
node->left->right = node->right;
node->right->left = node->left;
}
void link(FibNode* y, FibNode* x)
{
removeFromList(y);
y->parent = x;
if (!x->child)
{
x->child = y;
y->left = y->right = y;
}
else
{
y->right = x->child->right;
y->left = x->child;
x->child->right->left = y;
x->child->right = y;
}
x->degree++;
y->marked = false;
}
void consolidate()
{
int maxDeg = (int)(log2(nodeCount)) + 2;
std::vector<FibNode*> table(maxDeg + 1, nullptr);
std::vector<FibNode*> roots;
if (minNode)
{
roots.push_back(minNode);
FibNode* c = minNode->right;
while (c != minNode) { roots.push_back(c); c = c->right; }
}
for (FibNode* r : roots)
{
FibNode* x = r;
int d = x->degree;
while (d < (int)table.size() && table[d])
{
FibNode* y = table[d];
if (x->key > y->key) std::swap(x, y);
link(y, x);
table[d] = nullptr;
d++;
}
if (d >= (int)table.size()) table.resize(d + 1, nullptr);
table[d] = x;
}
minNode = nullptr;
for (FibNode* n : table)
{
if (n)
{
n->left = n->right = n;
if (!minNode) { minNode = n; }
else
{
addToRootList(n);
if (n->key < minNode->key) minNode = n;
}
}
}
}
void cutNode(FibNode* x, FibNode* y)
{
if (y->child == x)
{
y->child = (x->right == x) ? nullptr : x->right;
}
removeFromList(x);
y->degree--;
addToRootList(x);
x->parent = nullptr;
x->marked = false;
}
void cascadeCut(FibNode* node)
{
FibNode* p = node->parent;
if (p)
{
if (!node->marked) node->marked = true;
else { cutNode(node, p); cascadeCut(p); }
}
}
public:
FibonacciHeap() : minNode(nullptr), nodeCount(0) {}
void insert(int key)
{
FibNode* node = new FibNode(key);
addToRootList(node);
if (!minNode || node->key < minNode->key) minNode = node;
nodeCount++;
}
int findMin()
{
return minNode ? minNode->key : -1;
}
int extractMin()
{
FibNode* z = minNode;
if (!z) return -1;
if (z->child)
{
FibNode* c = z->child;
FibNode* start = c;
do
{
FibNode* next = c->right;
addToRootList(c);
c->parent = nullptr;
c = next;
} while (c != start);
}
removeFromList(z);
if (z == z->right) minNode = nullptr;
else { minNode = z->right; consolidate(); }
nodeCount--;
int k = z->key;
delete z;
return k;
}
void decreaseKey(FibNode* node, int newKey)
{
if (newKey > node->key) return;
node->key = newKey;
FibNode* p = node->parent;
if (p && node->key < p->key) { cutNode(node, p); cascadeCut(p); }
if (node->key < minNode->key) minNode = node;
}
bool isEmpty() { return minNode == nullptr; }
};
int main()
{
FibonacciHeap heap;
int values[] = {10, 20, 5, 15, 30, 3, 8};
for (int v : values)
{
heap.insert(v);
std::cout << "Inserted: " << v << "\n";
}
std::cout << "Min: " << heap.findMin() << "\n";
std::cout << "ExtractMin: " << heap.extractMin() << "\n";
std::cout << "New Min: " << heap.findMin() << "\n";
std::cout << "\nExtracting all:\n";
while (!heap.isEmpty())
{
std::cout << " " << heap.extractMin() << "\n";
}
return 0;
}
运行该程序将输出
Inserted: 10
Inserted: 20
Inserted: 5
Inserted: 15
Inserted: 30
Inserted: 3
Inserted: 8
Min: 3
ExtractMin: 3
New Min: 5
Extracting all:
5
8
10
15
20
30
C 完整实现
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <math.h>
#include <limits.h>
typedef struct FibNode
{
int key, degree;
bool marked;
struct FibNode *parent, *child, *left, *right;
} FibNode;
typedef struct
{
FibNode* minNode;
int count;
} FibHeap;
FibNode* newFibNode(int key)
{
FibNode* n = (FibNode*)malloc(sizeof(FibNode));
n->key = key; n->degree = 0; n->marked = false;
n->parent = n->child = NULL;
n->left = n->right = n;
return n;
}
FibHeap* newFibHeap()
{
FibHeap* h = (FibHeap*)malloc(sizeof(FibHeap));
h->minNode = NULL; h->count = 0;
return h;
}
void addToRootList(FibHeap* h, FibNode* n)
{
if (!h->minNode) { h->minNode = n; n->left = n->right = n; }
else
{
n->right = h->minNode->right;
n->left = h->minNode;
h->minNode->right->left = n;
h->minNode->right = n;
}
}
void removeFromList(FibNode* n)
{
n->left->right = n->right;
n->right->left = n->left;
}
void linkNodes(FibHeap* h, FibNode* y, FibNode* x)
{
removeFromList(y);
y->parent = x;
if (!x->child) { x->child = y; y->left = y->right = y; }
else
{
y->right = x->child->right;
y->left = x->child;
x->child->right->left = y;
x->child->right = y;
}
x->degree++;
y->marked = false;
}
void consolidate(FibHeap* h)
{
int maxD = (int)(log2(h->count)) + 2;
FibNode** table = (FibNode**)calloc(maxD + 1, sizeof(FibNode*));
FibNode* roots[128]; int rc = 0;
if (h->minNode)
{
roots[rc++] = h->minNode;
FibNode* c = h->minNode->right;
while (c != h->minNode) { roots[rc++] = c; c = c->right; }
}
for (int i = 0; i < rc; i++)
{
FibNode* x = roots[i]; int d = x->degree;
while (d <= maxD && table[d])
{
FibNode* y = table[d];
if (x->key > y->key) { FibNode* t = x; x = y; y = t; }
linkNodes(h, y, x);
table[d] = NULL; d++;
}
table[d] = x;
}
h->minNode = NULL;
for (int i = 0; i <= maxD; i++)
{
if (table[i])
{
table[i]->left = table[i]->right = table[i];
if (!h->minNode) h->minNode = table[i];
else
{
addToRootList(h, table[i]);
if (table[i]->key < h->minNode->key) h->minNode = table[i];
}
}
}
free(table);
}
void fibInsert(FibHeap* h, int key)
{
FibNode* n = newFibNode(key);
addToRootList(h, n);
if (n->key < h->minNode->key) h->minNode = n;
h->count++;
}
int fibFindMin(FibHeap* h) { return h->minNode ? h->minNode->key : -1; }
int fibExtractMin(FibHeap* h)
{
FibNode* z = h->minNode;
if (!z) return -1;
if (z->child)
{
FibNode* c = z->child;
FibNode* start = c;
do
{
FibNode* next = c->right;
addToRootList(h, c);
c->parent = NULL;
c = next;
} while (c != start);
}
removeFromList(z);
if (z == z->right) h->minNode = NULL;
else { h->minNode = z->right; consolidate(h); }
h->count--;
int k = z->key; free(z);
return k;
}
int main()
{
FibHeap* heap = newFibHeap();
int vals[] = {10, 20, 5, 15, 30, 3, 8};
int n = sizeof(vals) / sizeof(vals[0]);
for (int i = 0; i < n; i++)
{
fibInsert(heap, vals[i]);
printf("Inserted: %d\n", vals[i]);
}
printf("Min: %d\n", fibFindMin(heap));
printf("ExtractMin: %d\n", fibExtractMin(heap));
printf("New Min: %d\n", fibFindMin(heap));
printf("\nExtracting all:\n");
while (heap->minNode)
{
printf(" %d\n", fibExtractMin(heap));
}
free(heap);
return 0;
}
运行该程序将输出
Inserted: 10
Inserted: 20
Inserted: 5
Inserted: 15
Inserted: 30
Inserted: 3
Inserted: 8
Min: 3
ExtractMin: 3
New Min: 5
Extracting all:
5
8
10
15
20
30
Python 完整实现
import math
class FibNode:
def __init__(self, key):
self.key = key
self.degree = 0
self.marked = False
self.parent = None
self.child = None
self.left = self
self.right = self
class FibonacciHeap:
def __init__(self):
self.min_node = None
self.node_count = 0
def is_empty(self):
return self.min_node is None
def _add_to_root_list(self, node):
if self.min_node is None:
self.min_node = node
node.left = node.right = node
else:
node.right = self.min_node.right
node.left = self.min_node
self.min_node.right.left = node
self.min_node.right = node
def _remove_from_list(self, node):
node.left.right = node.right
node.right.left = node.left
def _link(self, y, x):
self._remove_from_list(y)
y.parent = x
if x.child is None:
x.child = y
y.left = y.right = y
else:
y.right = x.child.right
y.left = x.child
x.child.right.left = y
x.child.right = y
x.degree += 1
y.marked = False
def _consolidate(self):
max_deg = int(math.log2(self.node_count)) + 2
table = [None] * (max_deg + 1)
roots = []
if self.min_node:
roots.append(self.min_node)
c = self.min_node.right
while c != self.min_node:
roots.append(c)
c = c.right
for r in roots:
x = r
d = x.degree
while d < len(table) and table[d]:
y = table[d]
if x.key > y.key:
x, y = y, x
self._link(y, x)
table[d] = None
d += 1
if d >= len(table):
table.extend([None] * (d - len(table) + 1))
table[d] = x
self.min_node = None
for n in table:
if n:
n.left = n.right = n
if self.min_node is None:
self.min_node = n
else:
self._add_to_root_list(n)
if n.key < self.min_node.key:
self.min_node = n
def insert(self, key):
node = FibNode(key)
self._add_to_root_list(node)
if self.min_node is None or node.key < self.min_node.key:
self.min_node = node
self.node_count += 1
def find_min(self):
return self.min_node.key if self.min_node else None
def extract_min(self):
z = self.min_node
if z is None:
return None
if z.child:
child = z.child
start = child
while True:
nxt = child.right
self._add_to_root_list(child)
child.parent = None
if child == start:
break
child = nxt
self._remove_from_list(z)
if z == z.right:
self.min_node = None
else:
self.min_node = z.right
self._consolidate()
self.node_count -= 1
return z.key
def _cut(self, x, y):
if y.child == x:
y.child = x.right if x.right != x else None
self._remove_from_list(x)
y.degree -= 1
self._add_to_root_list(x)
x.parent = None
x.marked = False
def _cascade_cut(self, node):
p = node.parent
if p:
if not node.marked:
node.marked = True
else:
self._cut(node, p)
self._cascade_cut(p)
def decrease_key(self, node, new_key):
if new_key > node.key:
print("New key is greater than current key")
return
node.key = new_key
p = node.parent
if p and node.key < p.key:
self._cut(node, p)
self._cascade_cut(p)
if node.key < self.min_node.key:
self.min_node = node
def delete(self, node):
self.decrease_key(node, float('-inf'))
self.extract_min()
def main():
heap = FibonacciHeap()
values = [10, 20, 5, 15, 30, 3, 8]
for v in values:
heap.insert(v)
print(f"Inserted: {v}")
print(f"Min: {heap.find_min()}")
print(f"ExtractMin: {heap.extract_min()}")
print(f"New Min: {heap.find_min()}")
print("\nExtracting all:")
while not heap.is_empty():
print(f" {heap.extract_min()}")
if __name__ == "__main__":
main()
运行该程序将输出
Inserted: 10
Inserted: 20
Inserted: 5
Inserted: 15
Inserted: 30
Inserted: 3
Inserted: 8
Min: 3
ExtractMin: 3
New Min: 5
Extracting all:
5
8
10
15
20
30
Go 完整实现
package main
import (
"fmt"
"math"
)
type FibNode struct {
Key int
Degree int
Marked bool
Parent *FibNode
Child *FibNode
Left *FibNode
Right *FibNode
}
func newFibNode(key int) *FibNode {
n := &FibNode{Key: key}
n.Left = n
n.Right = n
return n
}
type FibHeap struct {
Min *FibNode
Count int
}
func newFibHeap() *FibHeap {
return &FibHeap{}
}
func (h *FibHeap) isEmpty() bool {
return h.Min == nil
}
func (h *FibHeap) addToRootList(node *FibNode) {
if h.Min == nil {
h.Min = node
node.Left = node
node.Right = node
} else {
node.Right = h.Min.Right
node.Left = h.Min
h.Min.Right.Left = node
h.Min.Right = node
}
}
func removeFromList(node *FibNode) {
node.Left.Right = node.Right
node.Right.Left = node.Left
}
func (h *FibHeap) link(y, x *FibNode) {
removeFromList(y)
y.Parent = x
if x.Child == nil {
x.Child = y
y.Left = y
y.Right = y
} else {
y.Right = x.Child.Right
y.Left = x.Child
x.Child.Right.Left = y
x.Child.Right = y
}
x.Degree++
y.Marked = false
}
func (h *FibHeap) consolidate() {
maxDeg := int(math.Log2(float64(h.Count))) + 2
table := make([]*FibNode, maxDeg+1)
var roots []*FibNode
if h.Min != nil {
roots = append(roots, h.Min)
cur := h.Min.Right
for cur != h.Min {
roots = append(roots, cur)
cur = cur.Right
}
}
for _, r := range roots {
x := r
d := x.Degree
for d < len(table) && table[d] != nil {
y := table[d]
if x.Key > y.Key {
x, y = y, x
}
h.link(y, x)
table[d] = nil
d++
}
for d >= len(table) {
table = append(table, nil)
}
table[d] = x
}
h.Min = nil
for _, n := range table {
if n != nil {
n.Left = n
n.Right = n
if h.Min == nil {
h.Min = n
} else {
h.addToRootList(n)
if n.Key < h.Min.Key {
h.Min = n
}
}
}
}
}
func (h *FibHeap) insert(key int) {
node := newFibNode(key)
h.addToRootList(node)
if h.Min == nil || node.Key < h.Min.Key {
h.Min = node
}
h.Count++
}
func (h *FibHeap) findMin() (int, bool) {
if h.Min == nil {
return 0, false
}
return h.Min.Key, true
}
func (h *FibHeap) extractMin() (int, bool) {
z := h.Min
if z == nil {
return 0, false
}
if z.Child != nil {
child := z.Child
start := child
for {
next := child.Right
h.addToRootList(child)
child.Parent = nil
if child == start {
break
}
child = next
}
}
removeFromList(z)
if z == z.Right {
h.Min = nil
} else {
h.Min = z.Right
h.consolidate()
}
h.Count--
return z.Key, true
}
func (h *FibHeap) cut(x, y *FibNode) {
if y.Child == x {
if x.Right == x {
y.Child = nil
} else {
y.Child = x.Right
}
}
removeFromList(x)
y.Degree--
h.addToRootList(x)
x.Parent = nil
x.Marked = false
}
func (h *FibHeap) cascadeCut(node *FibNode) {
p := node.Parent
if p != nil {
if !node.Marked {
node.Marked = true
} else {
h.cut(node, p)
h.cascadeCut(p)
}
}
}
func (h *FibHeap) decreaseKey(node *FibNode, newKey int) {
if newKey > node.Key {
fmt.Println("New key is greater than current key")
return
}
node.Key = newKey
parent := node.Parent
if parent != nil && node.Key < parent.Key {
h.cut(node, parent)
h.cascadeCut(parent)
}
if node.Key < h.Min.Key {
h.Min = node
}
}
func (h *FibHeap) delete(node *FibNode) {
h.decreaseKey(node, math.MinInt)
h.extractMin()
}
func main() {
heap := newFibHeap()
values := []int{10, 20, 5, 15, 30, 3, 8}
for _, v := range values {
heap.insert(v)
fmt.Printf("Inserted: %d\n", v)
}
if min, ok := heap.findMin(); ok {
fmt.Printf("Min: %d\n", min)
}
if val, ok := heap.extractMin(); ok {
fmt.Printf("ExtractMin: %d\n", val)
}
if min, ok := heap.findMin(); ok {
fmt.Printf("New Min: %d\n", min)
}
fmt.Println("\nExtracting all:")
for !heap.isEmpty() {
if val, ok := heap.extractMin(); ok {
fmt.Printf(" %d\n", val)
}
}
}
运行该程序将输出
Inserted: 10
Inserted: 20
Inserted: 5
Inserted: 15
Inserted: 30
Inserted: 3
Inserted: 8
Min: 3
ExtractMin: 3
New Min: 5
Extracting all:
5
8
10
15
20
30
斐波那契堆的性质
摊还时间复杂度
| 操作 | 二叉堆 | 二项式队列 | 斐波那契堆 |
|---|---|---|---|
| 插入(Insert) | O(log n) | O(log n) | O(1) |
| 查找最小值(FindMin) | O(1) | O(log n) | O(1) |
| 提取最小值(ExtractMin) | O(log n) | O(log n) | O(log n) |
| 减小键值(DecreaseKey) | O(log n) | O(log n) | O(1) |
| 删除(Delete) | O(log n) | O(log n) | O(log n) |
| 合并(Merge) | O(n) | O(log n) | O(1) |
斐波那契堆的优势场景
- 大量 decreaseKey 操作:Dijkstra 最短路径算法、Prim 最小生成树算法中,斐波那契堆将 decreaseKey 从 O(log n) 降为 O(1),使算法整体复杂度更优。
- Dijkstra 算法:O(V log V + E) vs 二叉堆的 O((V + E) log V)
- Prim 算法:同理获得更优的时间复杂度
- 大量合并操作:merge 为 O(1),优于二叉堆的 O(n)
实际使用注意
- 常数因子大:虽然摊还复杂度优秀,但常数因子较大,在小数据集上可能不如二叉堆。
- 实现复杂:斐波那契堆的实现远比二叉堆复杂,代码量大。
- 最坏情况:extractMin 的最坏情况是 O(n),但摊还 O(log n)。
- 实际应用:理论上最优,但实践中二叉堆或配对堆(Pairing Heap)通常表现更好。Python 的
heapq和 C++ 的std::priority_queue都使用二叉堆。

浙公网安备 33010602011771号