对于febonacci heap的分析:
1.extract-min,抽取最小结点花销O(D(n))。因为将min[H]抽取出时,需要实际花销O(D(n))将其子结点并入根表中;其次,合并同度根结点时,由于根表此时最多有T(n)+D(n)-1个根结点,故将同度根结点链接时T(n)+D(n)-1至多实际花销O(T(n)+D(n)),合并后根表至多有D(n)+1个根。利用势能分析法,平摊代价为O(D(n))。其实,由实际代价O(T(n)+D(n))平堆代价为D(n),其实是由根链接减少导致势能减少来支付的。
2.decrease-key,设联级删除c个结点,则根结点由T(n)变为T(n)+(c-1)+1,(c-1个联级点,1个x删除点),势能由T(n)+m(H)变为T(n)+c+2*(m(H)-c+2),故O(c)+4-c=O(1)代价。为什么级联删除c个结点的代价,却是O(1)呢?而不是最坏情况O(lgn)?原因是当删除一个内结点的孩子时,若marked=FALSE,则置为TRUE,有2个“能”,一个用于删除自己,一个用于存储至根,以便同度的根合并。
3.delete-key,调用一次O(1)的decreate-key和O(D(n))的extract-min,故代价为O(D(n))。
4.势能函数T(n)+2*m(H),其中T(n)为根结点、m(H)为marked为TRUE的结点。Why? 斐波那契堆有一个非常重要的性质:度为d的根结点至少有Fd+2个结点,(注:Fi为febonacci数,0 1 1 2 3 5 8 13 ...)以保持D(n)在logn级,这样extract-min和delete-key只需O(logn)。
如何保持此性质呢?1.两个度数相同的根堆合并成二项堆;2.当删除第二个非根结点的孩子时,将该结点移至根形成一新堆。以下为数学证明:
当删除一个结点x时,令y=parent[x]。若marked[y]=TRUE,表明y已经删除1个结点,设D(x)为x结点的度数,x为y的第i个结点,则按照1同度合并操作,当初x与y合并时,x和y都有i-1个度。y至多被删除1个结点,故第y的i个子结点至少有i-2个度。可证size(x)等于size(i)+1,其中,假设size(i)>=Fd+2,归纳法即可证明size(x)>=Fd+2。
又n >= Fd+2 >= 1.56^d,(后Fd+2 >= logn可证),故d<=log1.56(n),即logn。证毕。
这说明只要保证extract-min和delete-key就可lazily维护“松散"的斐波纳契堆性质。而其它时候对于其结构,则允许“无限”松散。
5.对于D(n)如何选取呢?
1.Dn = 1+8*sizeof(long)——由于利用long类型定义堆的度的个数sizeof(long)*8,考虑到可能合并后最大度+1,故二项树度最多不超过1+sizeof(long)*8。
2.利用ceillog2函数,求出当前树结点n的最大度lgn,再+2。
以下是我对于febonacci heap的实现源代码:
febonacci_heap.h源代码
#ifndef _FIBONACCI_HEAP
#define _FIBONACCI_HEAP
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
/*定义一个求有符号的无穷小的宏*/
#define SIGN_INFINITELY_SMALL(T) (1<<(8*sizeof(T)-1))
/*定义INT型的无穷小值*/
#define INT_INFINITELY_SMALL SIGN_INFINITELY_SMALL(int)
struct _targ_fb_heapnode;
#define swap(type, x, y) \
do{ \
type z = x; \
x = y; \
y = z; \
} while(0) \
/*定义堆结构*/
typedef struct _targ_fb_heap
{
int count; /*定义堆中结点各数*/
_targ_fb_heapnode* min; /*定义最根表结点*/
_targ_fb_heapnode* root; /*指向头结点,有了min,为何还须root呢?因为在遍历移除的时候很方便,始终保证指向一个根结点,而不用修改min*/
int dl; /*最大度*/
_targ_fb_heapnode** cons; /*指向最大度的内存区域*/
} FB_heap;
#define FB_HEAP_SIZE sizeof(FB_heap)
/*定义对FB_heap*操作*/
#define FB_HEAP_MIN(H) ((H)->min)
#define FB_IS_HEAP_EMPTY(H) (0 == (H)->count)
/*定义堆结点*/
typedef struct _targ_fb_heapnode
{
int key; /*定义关键字*/
int degree; /*定义结点度*/
struct _targ_fb_heapnode *left; /*双链表,将左兄弟链接起来*/
struct _targ_fb_heapnode *right; /*双链表,将右兄弟链接起来*/
struct _targ_fb_heapnode *parent; /*结点父亲*/
struct _targ_fb_heapnode *child; /*结点的第一个孩子*/
int marked :1; /*定义自从上次成为某孩子以来,是否已经被删除1个孩子*/
} FB_heap_node;
#define FB_NODE_SIZE sizeof(FB_heap_node)
/*定义堆结点操作*/
#define FB_IS_NODE_MARKED(N) ((N)->marked == 1)
#define FB_NODE_KEY_LT(x, y) ((x)->key < (y)->key) /*比较x与y的关键字大小*/
/*将x从双链表中移出*/
#define FB_NODE_REMOVE(x) do{ \
(x)->left->right = (x)->right; \
(x)->right->left = (x)->left; \
}while(0)
/*将x堆结点加入y结点之前*/
#define FB_NODE_ADD(x, y) do{ \
(x)->left = (y)->left; \
(x)->right = y; \
(y)->left->right = x; \
(y)->left = x; \
}while(0)\
/*申明函数*/
static inline int ceillog2(unsigned int t); /*求log2(t),且向上取整,并返回*/
FB_heap* fb_heap_make(); /*生成并返回一个已经初始化的fibonacci heap堆*/
void fb_heap_init(FB_heap *h); //初始化Heap
FB_heap_node* fb_heap_node_make(); /* 生成并返回一个已经初始化的结点 */
void fb_heap_node_init(FB_heap_node *x); /* 初始化结点x */
void fb_heap_insert(FB_heap *h, FB_heap_node *x); /*将堆结点x插入fibonacci heap中*/
FB_heap* fb_heap_union(FB_heap *h1, FB_heap *h2); /*将堆h1与h2合并,销毁h1和h2,并返回新堆h*/
FB_heap_node* fb_heap_extract_min(FB_heap *h); /*抽取堆中h并返回*/
void fb_heap_consolidate(FB_heap *h); /*当抽取一个最小结点之后,需要将等度的根结点合并*/
void fb_heap_link(FB_heap *h, FB_heap_node *x, FB_heap_node *y); /*将x根结点链接到y根结点*/
static FB_heap_node *fb_heap_min_remove(FB_heap *h); /*将堆的最小结点移出,并指向其左兄弟*/
static void fb_heap_cons_make(FB_heap *h); /*生成最大度的区域,为consolidate做准备*/
static void fb_heap_cons_destroy(FB_heap *h); /*销毁内存区域*/
FB_heap_node* fb_heap_search(const FB_heap * h, int key); /*查找等于某关键字的结点并返回,若未找到,返回NULL*/
static FB_heap_node* _fb_heap_search(FB_heap_node * const x, int key); /*为fb_heap_search所调用*/
void fb_heap_decrease_key(FB_heap *h, FB_heap_node *x, int key); /*将某个结点的度降为key*/
static void fb_heap_cut(FB_heap* h, FB_heap_node *x, FB_heap_node *y); /*将y的子孩子x移至根结点*/
static void fb_heap_cascading_cut(FB_heap* h, FB_heap_node *x); /*级联删除结点x,此时marked[x] = TRUE*/
void fb_heap_delete(FB_heap* h, FB_heap_node *x); /*删除某结点*/
void fb_heap_destroy(FB_heap* h); /*销毁堆*/
static void fb_heap_insert_keys(FB_heap *h, int keys[], int count); /* 插入多个关键字至heap中 */
static void fb_heap_insert_key(FB_heap *h, int key); /* 插入1个关键字至heap中 */
static void fb_heap_print(const FB_heap *h, char *info); /*打印堆,并附加打印说明信息*/
static void _fb_heap_print(FB_heap_node *x); /*被fb_heap_print内部调用*/
static void _fb_node_destroy(FB_heap_node* x); /*被fb_node_destroy内部调用,释放x所在的链表及其子孙*/
#endif
fibonacci_heap.cpp文件:
#include "fibonacci_heap.h"
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
static const char LogTable256[256] = {
#define LOG_NT(n) n, n+1, n+1, n+1, n+1, n+1, n+1, n+1, n+1, n+1, n+1, n+1, n+1, n+1, n+1, n+1
-1, 1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4,
LOG_NT(4), LOG_NT(5), LOG_NT(5), LOG_NT(6), LOG_NT(6), LOG_NT(6), LOG_NT(6),
LOG_NT(7), LOG_NT(7), LOG_NT(7), LOG_NT(7), LOG_NT(7), LOG_NT(7), LOG_NT(7), LOG_NT(7)
};
static inline int ceillog2(unsigned int v)
{
unsigned int tt = 0, t = 0, r = 0;
if(tt=v>>16)
{
r = (t = tt >> 8) ? 24 + LogTable256[t] : 16 + LogTable256[tt];
}
else
{
r = (t = v >> 8) ? 8 + LogTable256[t] : LogTable256[v];
}
return r;
}
FB_heap* fb_heap_make()
{
FB_heap* h = NULL;
if(!(h=(FB_heap *) malloc (FB_HEAP_SIZE)))
{
exit(-1);
}
fb_heap_init(h);
return h;
}
void fb_heap_init(FB_heap *h)
{
memset(h, 0, FB_HEAP_SIZE);
}
FB_heap_node* fb_heap_node_make()
{
FB_heap_node* x = NULL;
if(!(x = (FB_heap_node *) malloc (FB_NODE_SIZE)))
{
exit(-1);
}
fb_heap_node_init(x);
return x;
}
void fb_heap_node_init(FB_heap_node *x)
{
memset(x, 0, FB_NODE_SIZE);
x->left = x->right = x;
}
void fb_heap_insert(FB_heap *h, FB_heap_node *x)
{
if(FB_IS_HEAP_EMPTY(h))
{
h->min = x;
h->root = x;
}
else
{
/* 更新结点指针 */
FB_NODE_ADD(x, h->min);
x->parent = NULL;
/* 更新最小指针 */
if(FB_NODE_KEY_LT(x,h->min))
{
h->min = x;
}
}
h->count++;
}
FB_heap_node* fb_heap_extract_min(FB_heap *h)
{
FB_heap_node *w = NULL, *z = h->min;
if(z != NULL)
{
/*将z的孩子移至根*/
w = z->child;
while(w != NULL){
/*将x从z中移出*/
FB_NODE_REMOVE(w);
/*更新z的孩子指针*/
z->child = (w->left != w) ? w->left: NULL;
/*将x插入至z之前*/
FB_NODE_ADD(w, z);
w->parent = NULL;
w = z->child;
}
/*将z从堆中移除*/
FB_NODE_REMOVE(z);
if(z == z->left)
{/*若此时整个堆只有一个结点z*/
h->min = NULL;
}
else
{
h->min = z->left;
fb_heap_consolidate(h); /*在此函数中将会更新h->min*/
}
h->count--;
} /*if*/
return z;
}
void fb_heap_consolidate(FB_heap *h)
{
int i = 0, D = 0, d = 0;
FB_heap_node *w = h->min, *x = NULL, *y = NULL;
fb_heap_cons_make(h);
D = h->dl + 1;
for(i=0; i < D; i++)
{
*(h->cons + i) = NULL;
}
/*合并相同度的根结点*/
while(NULL != h->min)
{
x = fb_heap_min_remove(h);
d = x->degree;
while(NULL != *(h->cons + d))
{
y = *(h->cons + d);
if(x->key > y->key)
{
swap(FB_heap_node *,x, y);
}
fb_heap_link(h, y, x);
*(h->cons + d) = NULL;
d++;
}
*(h->cons + d) = x;
}
h->min = NULL;
/*将h->cons中的结点都重新加至根表中*/
for(i = 0; i < D; i++)
{
if(*(h->cons+i) != NULL)
{
if(h->min == NULL)
{
h->min = *(h->cons+i);
} //if
else
{
/* 更新结点指针 */
FB_NODE_ADD(*(h->cons+i), h->min);
/* 更新最小指针 */
if(FB_NODE_KEY_LT(*(h->cons+i),h->min))
{
h->min = *(h->cons+i);
} /*if*/
} /*else*/
} /*if*/
} /*for*/
}
void fb_heap_link(FB_heap *h, FB_heap_node *x, FB_heap_node *y)
{
FB_NODE_REMOVE(x);
if(y->child == NULL)
{
y->child = x;
}
else
{
FB_NODE_ADD(x, y->child);
}
x->parent = y;
y->degree++;
x->marked = FALSE;
}
FB_heap_node* fb_heap_search(const FB_heap *h, int key)
{
return _fb_heap_search(h->min, key);
}
void fb_heap_decrease_key(FB_heap *h, FB_heap_node *x, int key)
{
FB_heap_node *y = x->parent;
if(x->key < key)
{
exit(-1);
}
x->key = key;
/*由于x的key小于y的key,破坏了最小堆的性质,故需要进行删除处理*/
if((y != NULL) && x->key < y->key)
{
fb_heap_cut(h, x, y);
fb_heap_cascading_cut(h, y);
}
if(x->key < h->min->key)
{
h->min = x;
}
}
void fb_heap_delete(FB_heap* h, FB_heap_node *x)
{
fb_heap_decrease_key(h, x, INT_INFINITELY_SMALL);
fb_heap_extract_min(h);
}
void fb_heap_destroy(FB_heap* h)
{
_fb_node_destroy(h->min);
free(h);
h = NULL;
}
static void _fb_node_destroy(FB_heap_node* x)
{
FB_heap_node *p = x , *q = NULL;
while(p != NULL)
{
_fb_node_destroy(p->child);
q = p;
if(p == x)
{
p = NULL;
}
else
{
p = p->left;
}
free(q->right);
}
}
static void fb_heap_cut(FB_heap* h, FB_heap_node *x, FB_heap_node *y)
{
FB_NODE_REMOVE(x);
/*更新y的度及孩子指针*/
y->degree--;
if(y->child == x)
{
y->child = (x == x->left) ? NULL : x->left;
}
/*将x插入至根表中*/
x->parent = NULL;
x->left = x->right = x;
x->marked = FALSE;
FB_NODE_ADD(x, h->min);
}
static void fb_heap_cascading_cut(FB_heap* h, FB_heap_node *y)
{
FB_heap_node *z = y->parent;
if(y->marked == FALSE)
{
y->marked = TRUE;
}
else if(z != NULL)
{
fb_heap_cut(h, y, z);
fb_heap_cascading_cut(h, z);
}
}
static FB_heap_node* _fb_heap_search(FB_heap_node * const x, int key)
{
FB_heap_node *w = x, *y = NULL;
if(x != NULL)
{
/*遍历x所在的兄弟链表*/
do{
if(w->key == key)
{
y = w;
break;
}
else if(NULL != (y = _fb_heap_search(w->child, key)))
{
break;
}
w = w->left;
} while(w != x);
}/*if*/
return y;
}
static FB_heap_node *fb_heap_min_remove(FB_heap *h)
{
FB_heap_node *min = h->min;
if(min != NULL)
{
if(h->min == min->left)
{
h->min = NULL;
}
else
{
FB_NODE_REMOVE(min);
h->min = min->left;
}
min->left = min->right = min;
}
return min;
}
static void fb_heap_cons_make(FB_heap *h)
{
int od = h->dl;
h->dl = ceillog2(h->count) + 1;
if(od < h->dl)
{
/*1+最大度,因为度为h->dl可能被合并,+1*/
h->cons = (FB_heap_node **) realloc (h->cons, sizeof(FB_heap *) * (h->dl+1));
}
if(h->cons == NULL)
exit(-1);
}
static void fb_heap_insert_keys(FB_heap *h, int keys[], int count)
{
int i = 0;
for(i = 0; i < count; i++)
{
fb_heap_insert_key(h, keys[i]);
}
}
static void fb_heap_insert_key(FB_heap *h, int key)
{
FB_heap_node *x = NULL;
x = fb_heap_node_make();
x->key = key;
fb_heap_insert(h, x);
}
static void fb_heap_print(const FB_heap *h, char *info)
{
printf("%s\n", info);
printf("the fibonacci heap's info:\n");
printf("the count:%d\n", h->count);
_fb_heap_print(h->min);
printf("\n\n");
}
static void _fb_heap_print(FB_heap_node *x)
{
FB_heap_node *p = NULL;
if(x == NULL)
return;
p = x;
do
{
printf("(");
printf("%d", p->key);
if(p->child != NULL)
_fb_heap_print(p->child);
printf(")");
p = p->left;
}while(x != p);
}
/************************************************************************/
/* 测试部分 */
/************************************************************************/
#define KEYS_NUM 10
int keys[KEYS_NUM] = {1, 2, 3, 4, 5, 6, 7, 9, 10, 11};
int main()
{
FB_heap *h = NULL;
FB_heap_node *x = NULL;
#define BUF_SIZE 256
char buf[BUF_SIZE] = {0,};
h = fb_heap_make();
fb_heap_insert_keys(h, keys, KEYS_NUM);
fb_heap_print(h, "create the heap~");
x = fb_heap_extract_min(h);
sprintf(buf, "afther extract the min:%d~", x->key);
fb_heap_print(h, buf);
x = fb_heap_search(h, 11);
if(NULL != x)
{
sprintf(buf, "search the key:%d successfully~", x->key);
printf("%s\n\n", buf);
fb_heap_decrease_key(h, x, 8);
sprintf(buf, "decrease the key to %d successfully~", x->key);
fb_heap_print(h, buf);
}
x = fb_heap_search(h, 7);
if(NULL != x)
{
sprintf(buf, "delete the key to %d successfully~", x->key);
fb_heap_delete(h, x);
fb_heap_print(h, buf);
}
fb_heap_destroy(h);
return 0;
}
运行截图:
一份比较完善的开源代码:
http://download.youkuaiyun.com/source/3567665
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Copy::对于利用斐波那契堆实现Prime算法的时间复杂度分析:
Prim's algorithm select the edge with the lowest weight between the group of vortexes already selected and the rest of the vortexes.
So to implement Prim's algorithm, you need a minimum heap. Each time you select an edge you add the new vortex to the group of vortexes you've already chosen, and all its adjacent edges go into the heap.
Then you choose the edge with the minimum value again from the heap.
So the times we get are:
Fibonacci:
Choosing minimum edge = O(time of removing minimum) = O(log(E)) = O(log(V))
Inserting edges to heap = O(time of inserting item to heap) = 1
Min heap:
Choosing minimum edge = O(time of removing minimum from heap) = O(log(E)) = O(log(V))
Inserting edges to heap = O(time of inserting item to heap) = O(log(E)) = O(log(V))
(Remember that E =~ V^2 ... so log(E) == log(V^2) == 2Log(V) = O(log(V))
So, in total you have E inserts, and V minimum choosings (It's a tree in the end).
So in Min heap you'll get:
O(Vlog(V) + Elog(V)) == O(Elog(V))
And in Fibonacci heap you'll get:
O(Vlog(V) + E)