斐波那契堆是由一组最小堆有序树构成的。每个节点的度数为其子节点的数目。
树的度数为其根节点的度数。
斐波那契堆中的树都是有根的但是无序。每个节点x包含指向父节点的指针p[x]和指向任意一个子结点的child[x]。
x的所有子节点都用双向循环链表链接起来,叫做x的子链表。
子链表中的每一个节点y都有指向它的左兄弟的left[y]和右兄弟的right[y]。如果节点y是x仅有的子节点,则left[y]=right[y]=y。
斐波那契堆中所有树的根节点也用一个双向循环链表链接起来。
使用一个指针指向斐波那契堆中最小元素。
建立一个新的斐波纳契堆
每个结点x的域
- 父节点p[x]
- 指向任一子女的指针child[x]——结点x的子女被链接成一个环形双链表,称为x的子女表
- 左兄弟left[x]
- 右兄弟right[x]——当left[x] = right[x] = x时,说明x是独子。
- 子女的个数degree[x]
- 布尔值域mark[x]——标记是否失去了一个孩子
//斐波那契结点ADT
struct FibonacciHeapNode {
int key; //结点
int degree; //度
FibonacciHeapNode * left; //左兄弟
FibonacciHeapNode * right; //右兄弟
FibonacciHeapNode * parent; //父结点
FibonacciHeapNode * child; //第一个孩子结点
bool marked; //是否被删除第1个孩子
};
typedef FibonacciHeapNode FibNode;
对于一个给定的斐波那契堆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;
创建一个斐波那契堆
类似于二项堆的操作,分配并返回一个Fib对象H,取H.n = 0 , H.min = NIL ,H中没有树。花费为O(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;
}
插入一个节点
创建一个仅包含一个节点的新的斐波纳契堆,然后执行堆合并。
下面的代码是插入结点x到斐波那契堆H中,假设该结点已经被分配,并且x被赋值。时间复杂度:O(1)
如上图中,插入结点x.key=21。
1-4:初始化结点x
5-7:如果斐波那契堆为空,那么就直接将x结点插入H堆中的根链表,并且H.min指向x结点
8-10:H不为空时,首先将结点x插入到H堆中的根链表中,将x与堆中最小元素做比较,如果更小,则H.min指向x,否则不做任何改变。最后n加一。
//堆结点x插入fibonacci heap中
void FibHeapInsert(FibHeap * heap, FibNode * x) {
if (0 == heap->keyNum) {
heap->min = x;
} else {
FibNodeAdd(x, heap->min);
x->parent = NULL;
if (x->key < heap->min->key) {
heap->min = x;
}
}
heap->keyNum++;
}
//将数组内的值插入Fibonacci Heap
void FibHeapInsertKeys(FibHeap * heap, int keys[], int keyNum) {
for (int i = 0; i < keyNum; i++) {
FibHeapInsertKey(heap, keys[i]);
}
}
//将值插入Fibonacci Heap
static void FibHeapInsertKey(FibHeap * heap, int key) {
FibNode * x = NULL;
x = FibHeapNodeMake();
x->key = key;
FibHeapInsert(heap, x);
}
查找最小的节点
由于用一个指针指向了具有最小值的根节点,因此查找最小的节点是平凡的操作。
合并两个斐波纳契堆
简单合并两个斐波纳契堆的根表。即把两个斐波纳契堆的所有树的根首尾衔接并置。
下面的代码中表示合并两个斐波那契堆H1和H2,并且摧毁H1和H2。要做的仅仅是将他们的根链表结合起来,并且确定新的最小的元素。复杂度:O(1)
取出最小元素
这个操作是本节内最复杂的一个了。 操作复杂度为O(lgn).先看
3-6:将最小结点的孩子存入到根链表中,并且从链表中删除z
7-8:如果z的右兄弟等于z的话,说明z没有孩子,且原堆中只有z一个结点,则删除z后为空。
9-11:如果不止z一个的话,那么将H.min随意指向链表中的一个元素,不一定要是链表中最小的,然后执行CONSOLIDATE(H)
对于取出最小结点的整体操作我们知道了,但对于CONSOLIDATE(H)的具体操作还完全不知,下面我们就来介绍他。
CONSOLIDATE过程要做的工作是:使每个度数的二项树唯一,也就是使每个根都有一个不同的degree值为止。对根表的合并过程是反复执行下面的步骤:
1)在根表中找出两个具有相同度数的根x和y,且key[x] <= key[y].
2) 将y链接到x:将y从根表中移出,成为x的一个孩子。这个过程由FIB-HEAP-LINK完成。
首先看伪代码:
解释下上面的伪代码:
1-3:初始化一个数组A,其中D(H.n)=lgn,因为我们要使得每个根的度数唯一,而根最多有度数最大为lgn
4-14:使得链表中的树根度数唯一
15-23:重新建立一个树根表,保存数组A[i]中的根结点,并且找出最小的元素用H.min指向该元素。
可能单纯根据伪代码还很难理解,下面我们根据具体流程图来分析。
他的操作流程可以参照下图。
a-b:就是删除最小元素3,并且将他的孩子存入根链表中
c-k:从H.min指向的根结点开始向右遍历,并按照其度数存入对应的数组A中的位置,当所存入的位置不为空,则说明存在相同度数的根结点,于是就执行FIB-HEAP-LINK操作,将他们结合起来,然后继续遍历。
l-k:找出链表中最小的元素,H.min指向该元素。
减少元素的值
下面的伪代码是将x节点的值减少到k
5-7:当节点减少后的值小于他的父节点,那么就要进行调整,首先是执行CUT(H,x,y)操作,即将x节点放到根链表中。然后执行CASCADING-CUT(H,y)操作,即使得斐波那契堆中的树不是那么不像二项树。下面是对该操作的详细解释:
- 由于增加了删除和关键字减值操作,所以,F堆中的最小树就不一定必须是二项树了。事实上,可能存在度为k却只有k + 1(一棵所有叶子节点的)个结点的最小树。为了保证每个度为k的最小树至少包含ck个结点(c > 1), 每次执行删除操作和关键字减值操作后,还必须进行级联剪枝操作。为此,为每个结点增加一个布尔类型的child_cut域(即本文里的marked)。child_cut域的值仅对那些不是最小树树根的结点有意义。对于不是最小树树根的结点x, x的child_cut域为TRUE,当且仅当在最近一次x成为其当前父结点的儿子之后,x的一个儿子被删除。这就意味着,在执行删除最小元素中,每次连接两棵最小树时,关键字值较大的根结点的child_cut域应该赋值为FALSE。更进一步地说,一旦删除操作或关键字减值操作将最小树的非根结点q从其所在双向链表中删除时,则调用级联剪枝操作。在执行级联剪枝操作过程中,检查从被删除结点q的父节点p开始,到被删节点的最近的child_cut域为FALSE的祖先结点的路径。对在该路径上所有child_cut域为TRUE的非根结点,将其从所在的双向链表中删除,并将其加入到F堆的最小树的根节点组成的双向链表中。如果该路径上存在child_cut域为FALSE的结点 ,则将其该域的值修改为TRUE。
下图中是上面代码中的操作流程。
释放(删除)最小的节点
分为三步:
- 查找最小的根节点并删除它,其所有的子节点都加入堆的根表,即它的子树都成为堆所包含的树;
- 需要查找并维护堆的最小根节点,但这耗时较大。为此,同时完成堆的维护:对堆当前包含的树的度数从低到高,迭代执行具有相同度数的树的合并并实现最小树化调整,使得堆包含的树具有不同的度数。这一步使用一个数组,数组下标为根节点的度数,数组的值为指向该根节点指针。如果发现具有相同度数的其他根节点则合并两棵树并维护该数组的状态。
- 对当前堆的所有根节点查找最小的根节点。
降低一个节点的键值
对一个节点的键值降低后,自键值降低的节点开始自下而上的迭代执行下述操作,直至到根节点或一个未被标记(marked)节点为止:
如果当前节点键值小于其父节点的键值,则把该节点及其子树摘下来作为堆的新树的根节点;其原父节点如果是被标记(marked)节点,则也被摘下来作为堆的新树的根节点;如果其原父节点不是被标记(marked)节点且不是根节点,则其原父节点被加标记。
如果堆的新树的根节点被标记(marked),则去除该标记。
删除节点
把被删除节点的键值调整为负无穷小,然后执行“降低一个节点的键值”算法,然后再执行“删除最小节点”算法。
一个斐波那契堆是一系列具有最小堆序(min-heap ordered)的有根树的集合。也就是说,每棵树遵循最小堆性质:每个结点的关键字大于或等于它的父节点的关键字,如下图:
转载:
-
-
-
- #include
- #include
- #include
- #include
- #include
- using namespace std;
-
-
- struct FibonacciHeapNode {
- int key;
- int degree;
- FibonacciHeapNode * left;
- FibonacciHeapNode * right;
- FibonacciHeapNode * parent;
- FibonacciHeapNode * child;
- bool marked;
- };
-
- typedef FibonacciHeapNode FibNode;
-
-
- struct FibonacciHeap {
- int keyNum;
- FibonacciHeapNode * min;
- int maxNumOfDegree;
- FibonacciHeapNode * * cons;
- };
-
- typedef FibonacciHeap FibHeap;
-
-
-
- inline void FibNodeRemove(FibNode * x);
-
-
- void FibNodeAdd(FibNode * x, FibNode * y);
-
-
- FibHeap * FibHeapMake() ;
-
-
- FibNode * FibHeapNodeMake();
-
-
- void FibHeapInsert(FibHeap * heap, FibNode * x);
-
-
- void FibHeapInsertKeys(FibHeap * heap, int keys[], int keyNum);
-
-
- static void FibHeapInsertKey(FibHeap * heap, int key);
-
-
- FibNode * FibHeapExtractMin(FibHeap * heap);
-
-
- void FibHeapConsolidate(FibHeap * heap);
-
-
- void FibHeapLink(FibHeap * heap, FibNode * x, FibNode *y);
-
-
- static void FibHeapConsMake(FibHeap * heap);
-
-
- static FibNode *FibHeapMinRemove(FibHeap * heap);
-
-
- void FibHeapDecrease(FibHeap * heap, FibNode * x, int key);
-
-
- static void FibHeapCut(FibHeap * heap, FibNode * x, FibNode * y);
-
-
- static void FibHeapCascadingCut(FibHeap * heap, FibNode * y);
-
-
- void renewDegree(FibNode * parent, int degree);
-
-
- void FibHeapDelete(FibHeap * heap, FibNode * x);
-
-
- FibNode * FibHeapSearch(FibHeap * heap, int key);
-
-
- static FibNode * FibNodeSearch(FibNode * x, int key);
-
-
- void FibHeapDestory(FibHeap * heap);
-
-
- static void FibNodeDestory(FibNode * x);
-
-
- static void FibHeapPrint(FibHeap * heap);
-
-
- static void FibNodePrint(FibNode * x);
-
-
-
- inline void FibNodeRemove(FibNode * x) {
- x->left->right = x->right;
- x->right->left = x->left;
- }
-
-
-
-
-
-
- inline void FibNodeAdd(FibNode * x, FibNode * y) {
- x->left = y->left;
- y->left->right = x;
- x->right = y;
- y->left = x;
- }
-
-
- 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;
- }
-
-
- 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;
- }
-
-
- void FibHeapInsert(FibHeap * heap, FibNode * x) {
- if (0 == heap->keyNum) {
- heap->min = x;
- } else {
- FibNodeAdd(x, heap->min);
- x->parent = NULL;
- if (x->key < heap->min->key) {
- heap->min = x;
- }
- }
- heap->keyNum++;
- }
-
-
- void FibHeapInsertKeys(FibHeap * heap, int keys[], int keyNum) {
- for (int i = 0; i < keyNum; i++) {
- FibHeapInsertKey(heap, keys[i]);
- }
- }
-
-
- static void FibHeapInsertKey(FibHeap * heap, int key) {
- FibNode * x = NULL;
- x = FibHeapNodeMake();
- x->key = key;
- FibHeapInsert(heap, x);
- }
-
-
- FibNode * FibHeapExtractMin(FibHeap * heap) {
- FibNode * x = NULL, * z = heap->min;
- if (z != NULL) {
-
-
- while (NULL != z->child) {
- x = z->child;
- FibNodeRemove(x);
- if (x->right == x) {
- z->child = NULL;
- } else {
- z->child = x->right;
- }
- FibNodeAdd(x, z);
- x->parent = NULL;
- }
-
- FibNodeRemove(z);
- if (z->right == z) {
- heap->min = NULL;
- } else {
- heap->min = z->right;
- FibHeapConsolidate(heap);
- }
- heap->keyNum--;
- }
- return z;
- }
-
-
- void FibHeapConsolidate(FibHeap * heap) {
- int D, d;
- FibNode * w = heap->min, * x = NULL, * y = NULL;
- FibHeapConsMake(heap);
- D = heap->maxNumOfDegree + 1;
- for (int i = 0; i < D; i++) {
- *(heap->cons + i) = NULL;
- }
-
-
- while (NULL != heap->min) {
- x = FibHeapMinRemove(heap);
- d = x->degree;
- while (NULL != *(heap->cons + d)) {
- y = *(heap->cons + d);
- if (x->key > y->key) {
- swap(x, y);
- }
- FibHeapLink(heap, y, x);
- *(heap->cons + d) = NULL;
- d++;
- }
- *(heap->cons + d) = x;
- }
- heap->min = NULL;
-
-
- for (int i = 0; i < D; i++) {
- if (*(heap->cons + i) != NULL) {
- if (NULL == heap->min) {
- heap->min = *(heap->cons + i);
- } else {
- FibNodeAdd(*(heap->cons + i), heap->min);
- if ((*(heap->cons + i))->key < heap->min->key) {
- heap->min = *(heap->cons + i);
- }
- }
- }
- }
- }
-
-
- void FibHeapLink(FibHeap * heap, FibNode * x, FibNode *y) {
- FibNodeRemove(x);
- if (NULL == y->child) {
- y->child = x;
- } else {
- FibNodeAdd(x, y->child);
- }
- x->parent = y;
- y->degree++;
- x->marked = false;
- }
-
-
- static void FibHeapConsMake(FibHeap * heap) {
- int old = heap->maxNumOfDegree;
- heap->maxNumOfDegree = int(log(heap->keyNum * 1.0) / log(2.0)) + 1;
- if (old < heap->maxNumOfDegree) {
-
- heap->cons = (FibNode **) realloc(heap->cons,
- sizeof(FibHeap *) * (heap->maxNumOfDegree + 1));
- if (NULL == heap->cons) {
- puts("Out of Space!");
- exit(1);
- }
- }
- }
-
-
- static FibNode *FibHeapMinRemove(FibHeap * heap) {
- FibNode *min = heap->min;
- if (heap->min == min->right) {
- heap->min = NULL;
- } else {
- FibNodeRemove(min);
- heap->min = min->right;
- }
- min->left = min->right = min;
- return min;
- }
-
-
- void FibHeapDecrease(FibHeap * heap, FibNode * x, int key) {
- FibNode * y = x->parent;
- if (x->key < key) {
- puts("new key is greater than current key!");
- exit(1);
- }
- x->key = key;
-
- if (NULL != y && x->key < y->key) {
-
- FibHeapCut(heap, x, y);
- FibHeapCascadingCut(heap, y);
- }
- if (x->key < heap->min->key) {
- heap->min = x;
- }
- }
-
-
- static void FibHeapCut(FibHeap * heap, FibNode * x, FibNode * y) {
- FibNodeRemove(x);
- renewDegree(y, x->degree);
- if (x == x->right) {
- y->child = NULL;
- } else {
- y->child = x->right;
- }
- x->parent = NULL;
- x->left = x->right = x;
- x->marked = false;
- FibNodeAdd(x, heap->min);
- }
-
-
- static void FibHeapCascadingCut(FibHeap * heap, FibNode * y) {
- FibNode * z = y->parent;
- if (NULL != z) {
- if (y->marked == false) {
- y->marked = true;
- } else {
- FibHeapCut(heap, y, z);
- FibHeapCascadingCut(heap, z);
- }
- }
- }
-
-
- void renewDegree(FibNode * parent, int degree) {
- parent->degree -= degree;
- if (parent-> parent != NULL) {
- renewDegree(parent->parent, degree);
- }
- }
-
-
- void FibHeapDelete(FibHeap * heap, FibNode * x) {
- FibHeapDecrease(heap, x, INT_MIN);
- FibHeapExtractMin(heap);
- }
-
-
- FibNode * FibHeapSearch(FibHeap * heap, int key) {
- return FibNodeSearch(heap->min, key);
- }
-
-
- static FibNode * FibNodeSearch(FibNode * x, int key) {
- FibNode * w = x, * y = NULL;
- if (x != NULL) {
- do {
- if (w->key == key) {
- y = w;
- break;
- } else if (NULL != (y = FibNodeSearch(w->child, key))) {
- break;
- }
- w = w->right;
- } while (w != x);
- }
- return y;
- }
-
-
- void FibHeapDestory(FibHeap * heap) {
- FibNodeDestory(heap->min);
- free(heap);
- heap = NULL;
- }
-
-
- static void FibNodeDestory(FibNode * x) {
- FibNode * p = x, *q = NULL;
- while (p != NULL) {
- FibNodeDestory(p->child);
- q = p;
- if (p -> left == x) {
- p = NULL;
- } else {
- p = p->left;
- }
- free(q->right);
- }
- }
-
-
- static void FibHeapPrint(FibHeap * heap) {
- printf("The keyNum = %d\n", heap->keyNum);
- FibNodePrint(heap->min);
- puts("\n");
- };
-
-
- static void FibNodePrint(FibNode * x) {
- FibNode * p = NULL;
- if (NULL == x) {
- return ;
- }
- p = x;
- do {
- printf(" (");
- printf("%d", p->key);
- if (p->child != NULL) {
- FibNodePrint(p->child);
- }
- printf(") ");
- p = p->left;
- }while (x != p);
- }
-
- int keys[10] = {1, 2, 3, 4, 5, 6, 7, 9, 10, 11};
-
- int main() {
- FibHeap * heap = NULL;
- FibNode * x = NULL;
- heap = FibHeapMake();
- FibHeapInsertKeys(heap, keys, 10);
- FibHeapPrint(heap);
-
- x = FibHeapExtractMin(heap);
- printf("抽取最小值%d之后:\n", x->key);
- FibHeapPrint(heap);
-
- x = FibHeapSearch(heap, 11);
- if (NULL != x) {
- printf("查找%d成功,", x->key);
- FibHeapDecrease(heap, x, 8);
- printf("减小到%d后:\n", x->key);
- FibHeapPrint(heap);
- }
-
- x = FibHeapSearch(heap, 7);
- if (NULL != x) {
- printf("删除%d成功:\n", x->key);
- FibHeapDelete(heap, x);
- FibHeapPrint(heap);
- }
-
- FibHeapDestory(heap);
- return 0;
- }