1.简介
斐波那契堆是一种松散的二项堆,与二项堆的主要区别在于构成斐波那契堆得树可以不是二项树,并且这些树的根排列是无序的(二项堆的根结点排序从左到右是按照结点个数排序的,不是按照根结点的大小)。
斐波那契堆得优势在于它对建堆、插入、抽取最小关键字、联合等操作能在O(1)的时间内完成(不涉及删除元素的操作仅需要O(1))。这是对二项堆效率的巨大改善。在EXACT-MIN|, DELETE的操作数目较小时,斐波那契堆是很理想的,例如:某些图问题算法对每条边都要调用一次DECREASE-KEY(图的最小割:Graph-cut:Min-Cut Problem )。对许多稠密图来说,每一次DECREASE-KEY调用的O(1)加起来,就是对二叉或者二项堆的最坏情况的一种显著改善。用于解决最小生成树和寻找单源最短路径等问题的快速算法都要用到斐波那契堆。
但是,从实际上看,对于大多数应用来说,由于斐波那契堆得常数因子以及程序设计上的复杂度,使它不如通常的二叉堆合适。因此,它的价值大多存在于理论意义上(如果设计出一种与斐波那契堆具有相同平摊时间界但又简单得多数据结构,那他就会有很大的实用价值)。
斐波那契堆如果不进行DECREASE-KEY,DELETE,则堆中的树与二项树一致。由于相对于二项堆,斐波那契堆更松散,合并操作只发生在抽取一个结点之后,也就是说斐波那契堆的维护可以(总是)被延后到方便时再做。
1.1斐波那契堆结点ADT
结点含有以下域:
1) 父节点p[x]
2) 指向任一子女的指针child[x]——结点x的子女被链接成一个环形双链表,称为x的子女表
3) 左兄弟left[x]
4) 右兄弟right[x]——当left[x] = right[x] = x时,说明x是独子。
5) 子女的个数degree[x]
6) 布尔值域mark[x]——标记是否失去了一个孩子
1.2斐波那契堆ADT
对于一个给定的斐波那契堆H,可以通过指向包含最小关键字的树根的指针min[H]来访问,这个结点被称为斐波那契堆中的最小结点。如果一个斐波那契堆H是空的,则min[H] = NIL. 在一个斐波那契堆中,所有树的根都通过left和right指针链接成一个环形的双链表,称为堆的根表。于是,指针min[H]就指向根表中具有最小关键字的结点(就是查找最小结点的操作,下文就没有再介绍了)。
//斐波那契堆ADT
struct FibonacciHeap {
int keyNum; //堆中结点个数
FibonacciHeapNode * min;//最小堆,根结点
int maxNumOfDegree; //最大度
FibonacciHeapNode * * cons;//指向最大度的内存区域
};
typedef FibonacciHeap FibHeap;
2.斐波那契堆操作
2.1.创建斐波那契堆
创建一个空的斐波那契堆,过程MAKE-FIB-HEAP 分配并返回一个斐波那契堆对象H;
//初始化一个空的Fibonacci Heap
FibHeap * FibHeapMake() {
FibHeap * heap = NULL;
heap = (FibHeap *) malloc(sizeof(FibHeap));
if (NULL == heap) {
puts("Out of Space!!");
exit(1);
}
memset(heap, 0, sizeof(FibHeap));
return heap;
}
//初始化结点x
FibNode * FibHeapNodeMake() {
FibNode * x = NULL;
x = (FibNode *) malloc(sizeof(FibNode));
if (NULL == x) {
puts("Out of Space!!");
exit(1);
}
memset(x, 0, sizeof(FibNode));
x->left = x->right = x;
return x;
}
2.2.插入一个结点
要插入一个结点x,对结点的各域初始化,赋值,然后构造自身的环形双向链表后,将x加入H的根表中。 也就是说,结点x 成为一棵单结点的最小堆有序树,同时就是斐波那契堆中一棵无序树而且在根表最小结点的左边。
如图是将关键字为21的结点插入斐波那契堆。该结点自成一棵最小堆有序树,从而被加入到根表中,成为根的左兄弟。
FIB-HEAP-INSERT(H, x)
1 degree[x] 0
2 p[x] NIL
3 child[x] NIL
4 left[x] x
5 right[x] x
6 mark[x] FALSE
7 concatenate the root list containing x with root list H
8 if min[H] = NIL or key[x] < key[min[H]]
9 then min[H] x
10 n[H] n[H] + 1
//堆结点x插入fibonacci heap中 void FibHeapInsert(FibHeap * heap, FibNode * x) { if (0 == heap->keyNum) { heap->min = x; } else { FibNodeAdd(x, heap->min); x->parent =