斐波那契堆
来源:互联网 发布:淘宝运动鞋店铺 编辑:程序博客网 时间: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)合并两个斐波那契堆中
该过程只是简单的将斐波那契堆H1和H2的两个根链表进行合并,然后确定一个新的最小结点。
//=============================================================// 将堆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. 在跟链表中找出两个具有相同度数的根x和y,且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
- 斐波那契堆
- 斐波那契堆
- 斐波那契堆
- 斐波那契堆
- 斐波那契堆
- 斐波那契堆
- 斐波那契堆
- 斐波那契堆
- 斐波那契堆
- 斐波那契堆
- 斐波那契堆
- 斐波那契堆
- 斐波那契堆
- 斐波那契堆
- 斐波那契堆
- 斐波那契堆
- 斐波那契堆的实现
- 算法之斐波那契堆
- CentOS6.5 将用户添加到sudoers里
- lihnux特殊装置 loop 挂载
- unable to bind to property 'money' on class 'Object' (class is not an IEventDispatcher)
- catalina.sh设置JAVA_HOME后还无法解决更换JDK有关问题
- KGLHD
- 斐波那契堆
- Oracle升级_oracle 10g版本由 10.2.0.1.0升级为10.2.0.4.0(即CPU升级)
- 3.1.5、准备卸载你的应用程序
- 我应该如何有效地学习linux?(持续更新)
- 使用lua螺旋打印数组
- Mac OS X下使用launchctl定时启动AppleScript脚本
- flex前端写的bean最好注册一下
- hdu 4771 状态压缩+bfs Stealing Harry Potter's Precious
- 数字语音信号处理的举例