斐波那契堆

来源:互联网 发布:淘宝运动鞋店铺 编辑:程序博客网 时间:2024/05/22 00:39
斐波那契堆
主要参考《算法导论》

1、斐波那契堆的结构

与二项堆一样,斐波那契堆是由一组最小堆的有序树构成,但堆中的树并不一定是二项树。与二项堆中树都是有序的不同,斐波那契堆中的树都是有根而无序的。

上图是一个由5棵最小堆有序树和14个结点构成的一个斐波那契堆。(A Fibonacci heap consisting of five min-heap-orderd trees and 14 nodes)

斐波那契堆的表示(实现)

typedef struct fhnode {int key;int degree; // the number of childrenbool mark;  // whether node x has lost a childstruct fhnode *parent;struct fhnode *child;struct fhnode *left;struct fhnode *right;} FHNode;typedef struct fibheap {int n;              // the number of nodes currently in Hstruct fhnode *min; // point to the root of a tree containing the minimum key} *FHeap;


2、斐波那契堆的操作



1)创建一个新的斐波那契堆

//=============================================================// 创建一个空堆//=============================================================FHeap FibHeapCreate(/*FHeap H*/){FHeap H = (struct fibheap*)malloc(sizeof(struct fibheap));if (!H) {printf("H malloc error\n");return NULL;}H->min = NULL;H->n = 0;return H;}

2)将结点x插入斐波那契堆中

//=============================================================// 将x结点插到cur结点前面(使用时,保证cur存在,即cur!=NULL)//=============================================================static inline void InsertNode(FHNode *x, FHNode *cur){cur->left->right = x;  x->left = cur->left;x->right = cur;cur->left = x;}//=============================================================// 将x结点从链表中移走//=============================================================static inline void RemoveNode(FHNode *x){x->left->right = x->right;x->right->left = x->left;}//=============================================================// 将含key值的结点插入堆中//=============================================================FHeap FibHeapInsert(FHeap H, int key){// 初始化新结点FHNode *x = (FHNode *)malloc(sizeof(FHNode));if (!x) {printf("x malloc error\n");return NULL;}x->key = key;x->degree = 0;x->parent = NULL;x->child = NULL;x->left = x->right = x;x->mark = false;if (H->min == NULL) { // 插入第一个结点H->min = x;} else {InsertNode(x, H->min); // 在根链表中插入x结点if (x->key < H->min->key)H->min = x;}H->n += 1;}

3)寻找最小结点

//=============================================================// 获得堆中key值最小的结点//=============================================================FHNode *FibHeapMinimum(FHeap H){return H->min;}

4)合并两个斐波那契堆中

该过程只是简单的将斐波那契堆H1H2的两个根链表进行合并,然后确定一个新的最小结点。

//=============================================================// 将堆H1与H2进行合并//=============================================================FHeap FibHeapUnion(FHeap H1, FHeap H2){FHeap H = FibHeapCreate();H->min = H1->min;FHNode *x = H->min;  // concatenate the root list of H2 with the root list of HFHNode *y = H2->min;if (x != NULL && y != NULL) {FHNode *xl = x->left;FHNode *yl= y->left;xl->right = y;y->left = xl;yl->right = x;x->left = yl;}// 确定H->min的位置if (H1->min == NULL || (H2->min != NULL && H2->min->key < H1->min->key))H->min = H2->min;H->n = H1->n + H2->n;return H;}

5)抽取最小结点

该操作会调用一个consolidate过程来对根链表中的树进行合并。

过程consolidate会使用一个辅助数组A[D(H.n)],并反复执行下面的步骤:

a. 在跟链表中找出两个具有相同度数的根xy,且x.key <= y.key;

b. y链接到x:将y从跟链表中移出,并让其成为x的孩子。

直到根链表中的每个根都有不同的degree值。




//=============================================================// 将y结点插入到x的孩子链表中//=============================================================static inline void FibHeapLink(FHeap H, FHNode *y, FHNode *x){RemoveNode(y);if (!x->child) { // x的孩子不存在x->child = y;y->left = y->right = y;} else {InsertNode(y, x->child);}x->degree += 1;y->parent = x;y->mark = false;}//=============================================================// 获得堆的最大度d = lg(n)//=============================================================static inline int GetMaxDegree(double n){return log(n) / log(1.618);}//=============================================================// 用于交换x与y//=============================================================static inline void SwapNode(FHNode **x, FHNode **y){FHNode *tmp = *x;*x = *y;*y = tmp;}//=============================================================// 合并根链表,减少堆中树的数目//=============================================================void Consolidate(FHeap H){// 构建数组A,用于根结点的合并int md = GetMaxDegree(H->n);FHNode **A = (FHNode **)malloc(sizeof(FHNode *) * (md + 1));if (!A) {printf("A malloc error\n");return ;}for (int i = 0; i <= md; i++)A[i] = NULL; FHNode *w = H->min;FHNode *last = NULL; // 用作结束的标记// 遍历根链表,找到度相同的两个树进行合并// 这里坑较多,写代码时,一定要小心if (w) last = w->left; // 记录结束点while (w) {FHNode *next = w->right; // 临时保存,用于迭代FHNode *x = w;int d = x->degree;while (d <= md && A[d] != NULL) {FHNode *y = A[d]; if (x->key > y->key) { // x与y进行交换,保证x为根SwapNode(&x, &y);}FibHeapLink(H, y, x); // x度数也加了1A[d] = NULL;d += 1;}A[d] = x;if (w == last) // 循环结束break;w = next;}// 根据A来重新构建堆,感觉遍历找到H->min最更省事H->min = NULL;for (int i = 0; i <= md; i++) {if (A[i] != NULL) {RemoveNode(A[i]);if (H->min == NULL) {A[i]->left = A[i]->right = A[i];H->min = A[i];} else {InsertNode(A[i], H->min);if (A[i]->key < H->min->key)H->min = A[i];}}}}//=============================================================// 提取堆中key值最小的结点//=============================================================FHNode *FibHeapExtractMin(FHeap H){FHNode *z = H->min;if (z != NULL) {FHNode *cp = z->child; // 将z的孩子插入根链表中while (z->degree--) {FHNode *next = cp->right;RemoveNode(cp);    // 先将cp从孩子链表中移除cp->parent = NULL;InsertNode(cp, z); // 再插入到根链表中cp = next;}// 合并根链表中的树if (z == z->right) {// 只有一个结点H->min = NULL;} else {H->min = z->right;RemoveNode(z); // 将z从跟链表中移除Consolidate(H);}H->n -= 1;}return z;}

6)减少一个关键字

这里实现起来较为容易,但理解起来有点难(尤其是mark值)。


//=============================================================// 将y的孩子x插入到根链表中(切除x)//=============================================================static inline void Cut(FHeap H, FHNode *x, FHNode *y){RemoveNode(x);y->degree -= 1;InsertNode(x, H->min);x->parent = NULL;x->mark = false;}//=============================================================// 级联切除父结点//=============================================================static inline void CascadingCut(FHeap H, FHNode *y){FHNode *z = y->parent;if (z) {if (y->mark == false)y->mark = true;else {Cut(H, y, z);CascadingCut(H, z);}}}//=============================================================// 将x结点中的x->key值降至key(x->key < key)//=============================================================void FibHeapDecreaseKey(FHeap H, FHNode *x, int key){if (key > x->key) {printf("new key is greater than current key\n");return ;}x->key = key;FHNode *y = x->parent;if (y && x->key < y->key) { // 考虑x非根结点,及(key < x->parent->key)情况Cut(H, x, y);CascadingCut(H, y);}if (x->key < H->min->key)H->min = x;}

7)删除一个结点

//=============================================================// 将x结点从堆中删除//=============================================================void FibHeapDelete(FHeap H, FHNode *x){FibHeapDecreaseKey(H, x, MINVAL);FibHeapExtractMin(H);}


下面是程序的完整代码

//===============================================================// 斐波那契堆的实现// 时间:2014/8/2//===============================================================#include <stdio.h>#include <stdlib.h>#include <math.h>#define MINVAL -0xfffftypedef struct fhnode {int key;int degree; // the number of childrenbool mark;  // whether node x has lost a childstruct fhnode *parent;struct fhnode *child;struct fhnode *left;struct fhnode *right;} FHNode;typedef struct fibheap {int n;              // the number of nodes currently in Hstruct fhnode *min; // point to the root of a tree containing the minimum key} *FHeap;//=============================================================// 创建一个空堆//=============================================================FHeap FibHeapCreate(/*FHeap H*/){FHeap H = (struct fibheap*)malloc(sizeof(struct fibheap));if (!H) {printf("H malloc error\n");return NULL;}H->min = NULL;H->n = 0;return H;}//=============================================================// 将x结点插到cur结点前面(使用时,保证cur存在,即cur!=NULL)//=============================================================static inline void InsertNode(FHNode *x, FHNode *cur){cur->left->right = x;  x->left = cur->left;x->right = cur;cur->left = x;}//=============================================================// 将x结点从链表中移走//=============================================================static inline void RemoveNode(FHNode *x){x->left->right = x->right;x->right->left = x->left;}//=============================================================// 将含key值的结点插入堆中//=============================================================FHeap FibHeapInsert(FHeap H, int key){// 初始化新结点FHNode *x = (FHNode *)malloc(sizeof(FHNode));if (!x) {printf("x malloc error\n");return NULL;}x->key = key;x->degree = 0;x->parent = NULL;x->child = NULL;x->left = x->right = x;x->mark = false;if (H->min == NULL) { // 插入第一个结点H->min = x;} else {InsertNode(x, H->min); // 在根链表中插入x结点if (x->key < H->min->key)H->min = x;}H->n += 1;}//=============================================================// 获得堆中key值最小的结点//=============================================================FHNode *FibHeapMinimum(FHeap H){return H->min;}//=============================================================// 将堆H1与H2进行合并//=============================================================FHeap FibHeapUnion(FHeap H1, FHeap H2){FHeap H = FibHeapCreate();H->min = H1->min;// FHNode *x = H->min;// FHNode *y = H2->min;// FHNode *yl = y->left;// x->left->right = y;// y->left = x->left;// x->left = yl;// yl->right = x;FHNode *x = H->min;  // concatenate the root list of H2 with the root list of HFHNode *y = H2->min;if (x != NULL && y != NULL) {FHNode *xl = x->left;FHNode *yl= y->left;xl->right = y;y->left = xl;yl->right = x;x->left = yl;}// 确定H->min的位置if (H1->min == NULL || (H2->min != NULL && H2->min->key < H1->min->key))H->min = H2->min;H->n = H1->n + H2->n;return H;}//=============================================================// 将y结点插入到x的孩子链表中//=============================================================static inline void FibHeapLink(FHeap H, FHNode *y, FHNode *x){RemoveNode(y);if (!x->child) { // x的孩子不存在x->child = y;y->left = y->right = y;} else {InsertNode(y, x->child);}x->degree += 1;y->parent = x;y->mark = false;}//=============================================================// 获得堆的最大度d = lg(n)//=============================================================static inline int GetMaxDegree(double n){return log(n) / log(1.618);}//=============================================================// 用于交换x与y//=============================================================static inline void SwapNode(FHNode **x, FHNode **y){FHNode *tmp = *x;*x = *y;*y = tmp;}//=============================================================// 合并根链表,减少堆中树的数目//=============================================================void Consolidate(FHeap H){// 构建数组A,用于根结点的合并int md = GetMaxDegree(H->n);FHNode **A = (FHNode **)malloc(sizeof(FHNode *) * (md + 1));if (!A) {printf("A malloc error\n");return ;}for (int i = 0; i <= md; i++)A[i] = NULL; FHNode *w = H->min;FHNode *last = NULL; // 用作结束的标记// 遍历根链表,找到度相同的两个树进行合并// 这里坑较多,写代码时,一定要小心if (w) last = w->left; // 记录结束点while (w) {FHNode *next = w->right; // 临时保存,用于迭代FHNode *x = w;int d = x->degree;while (d <= md && A[d] != NULL) {FHNode *y = A[d]; if (x->key > y->key) { // x与y进行交换,保证x为根SwapNode(&x, &y);}FibHeapLink(H, y, x); // x度数也加了1A[d] = NULL;d += 1;}A[d] = x;if (w == last) // 循环结束break;w = next;}// 根据A来重新构建堆,感觉遍历找到H->min最更省事H->min = NULL;for (int i = 0; i <= md; i++) {if (A[i] != NULL) {RemoveNode(A[i]);if (H->min == NULL) {A[i]->left = A[i]->right = A[i];H->min = A[i];} else {InsertNode(A[i], H->min);if (A[i]->key < H->min->key)H->min = A[i];}}}}//=============================================================// 提取堆中key值最小的结点//=============================================================FHNode *FibHeapExtractMin(FHeap H){FHNode *z = H->min;if (z != NULL) {FHNode *cp = z->child; // 将z的孩子插入根链表中while (z->degree--) {FHNode *next = cp->right;RemoveNode(cp);    // 先将cp从孩子链表中移除cp->parent = NULL;InsertNode(cp, z); // 再插入到根链表中cp = next;}// 合并根链表中的树if (z == z->right) {// 只有一个结点H->min = NULL;} else {H->min = z->right;RemoveNode(z); // 将z从跟链表中移除Consolidate(H);}H->n -= 1;}return z;}//=============================================================// 将y的孩子x插入到根链表中(切除x)//=============================================================static inline void Cut(FHeap H, FHNode *x, FHNode *y){RemoveNode(x);y->degree -= 1;InsertNode(x, H->min);x->parent = NULL;x->mark = false;}//=============================================================// 级联切除父结点//=============================================================static inline void CascadingCut(FHeap H, FHNode *y){FHNode *z = y->parent;if (z) {if (y->mark == false)y->mark = true;else {Cut(H, y, z);CascadingCut(H, z);}}}//=============================================================// 将x结点中的x->key值降至key(x->key < key)//=============================================================void FibHeapDecreaseKey(FHeap H, FHNode *x, int key){if (key > x->key) {printf("new key is greater than current key\n");return ;}x->key = key;FHNode *y = x->parent;if (y && x->key < y->key) { // 考虑x非根结点,及(key < x->parent->key)情况Cut(H, x, y);CascadingCut(H, y);}if (x->key < H->min->key)H->min = x;}//=============================================================// 将x结点从堆中删除//=============================================================void FibHeapDelete(FHeap H, FHNode *x){FibHeapDecreaseKey(H, x, MINVAL);FibHeapExtractMin(H);}//=============================================================// 在堆中查找包含key的结点//=============================================================FHNode *FibHeapSearch(FHNode *x, int key){FHNode *pos = x;FHNode *y = NULL;if (pos) {do {if (pos->key == key)return pos;else if (pos->child)y = FibHeapSearch(pos->child, key);pos = pos->right;} while (pos != x);}return y;}//=============================================================// 打印堆中所有结点的key值//=============================================================void FibHeapPrint(FHNode *x){FHNode *pos = x;if (pos) {do {printf("%d\t", pos->key);if (pos->child) {FibHeapPrint(pos->child);}pos = pos->right;} while (pos != x);}}//=============================================================// 从pos处开始打印循环双链表中的key值(调试时使用)//=============================================================void PrintDList(FHNode *pos){FHNode *cur = pos;if (cur) {printf("%d\t", cur->key);cur = cur->right;}while (cur != pos) {printf("%d\t", cur->key);cur = cur->right;}// if (cur) {// do {// printf("%d\t", cur->key);// cur = cur->right;// } while (cur != pos);// }// // if (cur) {// while (cur->right != pos) {// printf("%d\t", cur->key);// cur = cur->right;// }// if (cur) { // 打印最后一个结点// printf("%d\t", cur->key);// }// }printf("\n");}int main(){int arr[] = {45, 65, 23, 9, 6, 21, 97, 60, 23, 7, 90, 61, 123, 987, 51, 11}; // 9int len = sizeof(arr) / sizeof(arr[0]);FHeap H1 = FibHeapCreate();for (int i = 0; i < len - 5; i++) {printf("H1 insert:%d\n", arr[i]);FibHeapInsert(H1, arr[i]);}printf("\n");FHeap H2 = FibHeapCreate();for (int i = len - 5; i < len; i++) {printf("H2 insert:%d\n", arr[i]);FibHeapInsert(H2, arr[i]);}printf("\n");printf("Union:");FHeap H = FibHeapUnion(H1, H2);printf("PrintKey:\n");FibHeapPrint(H->min); printf("\n");printf("ExtractMinKey:\n");/*for (int i = 0; i < len; i++)*/ {FHNode *min = FibHeapExtractMin(H);printf("%d\n", min->key);}printf("PrintKey:\n");FibHeapPrint(H->min);printf("\n");printf("Search:\n");FHNode *x = FibHeapSearch(H->min, 23);printf("%d\n", x->key);x = FibHeapSearch(H->min, 60);printf("%d\n", x->key);printf("DecreaseKey: %d-->3\n", x->key);FibHeapDecreaseKey(H, x, 3);printf("MinimumKey: ");FHNode *min = FibHeapMinimum(H);printf("%d\n", min->key);printf("DeleteKey: %d\n", min->key);FibHeapDelete(H, min);printf("ExtractMinKey: ");min = FibHeapExtractMin(H);printf("%d\n", min->key);system("pause");return 0;}

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 报关时通关单号没录怎么办 公司注销了行政许可证怎么办呢 报关项数超过50项怎么办 出口报关件数报多了怎么办 关税少交被海关缉私查到怎么办 外贸报关hs编码报错怎么办 报关金额少报了怎么办 进口报关金额少报了怎么办 报关重量报少了怎么办 金额报多100倍怎么办 ems没扫描到单号怎么办 回国海关被税了怎么办 代购买错东西了怎么办 征信报告有逾期怎么办 evus信息填错了怎么办 清关一个月了该怎么办 清关一直不发怎么办 清关一个月了怎么办 香港ems到西安海关税怎么办 寄东西被海关扣留怎么办 天津港新舱单品名错误核销怎么办 移动手机不能用联通卡怎么办 移动手机联通卡网速卡怎么办 移动手机不支持联通4g怎么办 汽车分离轴承异响怎么办 至尊宝被冻结了怎么办 qq冻结了至尊宝怎么办 至尊宝没办法申诉怎么办 至尊宝qq被冻结怎么办 未满16岁怎么办手机卡 联想预装的office卸载怎么办 win10激活后无法启动怎么办 移动电话卡没用了没注销怎么办 快捷快递客服热线一直打不通怎么办 牛奶乳加钙咀嚼片吃多了怎么办 三生骗了我该怎么办 国珍产品新时代卡怎么办 三个月大的宝宝对眼怎么办 9月大婴儿眼睛对眼怎么办 30岁眼部有皱纹怎么办 才24岁眼部皱纹怎么办