斐波那契堆 插入、 Extract-Min(查詢+刪除)效率與 STL優先佇列對比
阿新 • • 發佈:2019-01-01
插入 n個隨機資料,取m次最小值並pop掉
n=10000000(一千萬),m=0 (純插入,一個o1,一個logn)
fib:耗時8377ms
stl:耗時5086ms
n = 5000000(五百萬), m=20000(2萬)
fib:耗時4945ms
stl:耗時2605ms
n = 5000000(五百萬), m=2000000(2百萬)
fib:耗時15148ms
stl:耗時6069ms
n = 5000000(五百萬), m=0()
fib:耗時4290ms
stl:耗時2590ms
以上的隨機資料用rand()函式生成,測試環境是WIN7+I5筆記本
可以看出 在 這個規模下的 即使斐波那契堆的插入是 o(1),也並不能帶來特別明顯的優勢
原因可能如下,
1.這個fib是用 分散式記憶體實現的,(新加入的加點是用new獲取記憶體,這可能是一大原因)
2.fib堆本身操作常數因子就比較大,所以這個小規模下的資料並不能體現出複雜度的優勢 (o1 - lgn)
3.程式碼寫得太挫了。。。有時間自己再實現一遍吧
以下附上所用的fib程式碼: (網上找的+自己修改勉強跑起來的)
//說明: //程式碼中Fibonacci Heap 用變數heap表示 //結點通常用x,y等表示 #include<iostream> #include<cstdio> #include<cstdlib> #include<cmath> #include<climits> #include<windows.h> #include<time.h> #include<vector> using namespace std; struct node { int ff; int x,v; node(){} node( int a,int b) { x=a;v=b;} node(int c,int a,int b) {ff=c;x=a;v=b;} bool operator<(const node&b )const { return v<b .v; } bool operator>(const node&b )const { return v>b.v; } bool operator==(const node&b )const { return (v==b.v)&&(x==b.x); } }; node int_MIN; //斐波那契結點ADT struct FibonacciHeapNode { node key; //結點 int degree; //度 FibonacciHeapNode * left; //左兄弟 FibonacciHeapNode * right; //右兄弟 FibonacciHeapNode * parent; //父結點 FibonacciHeapNode * child; //第一個孩子結點 bool marked; //是否被刪除第1個孩子 }; typedef FibonacciHeapNode FibNode; //斐波那契堆ADT struct FibonacciHeap { int keyNum; //堆中結點個數 FibonacciHeapNode * min;//最小堆,根結點 int maxNumOfDegree; //最大度 FibonacciHeapNode * * cons;//指向最大度的記憶體區域 }; typedef FibonacciHeap FibHeap; /*****************函式申明*************************/ //將x從雙鏈表移除 inline void FibNodeRemove(FibNode * x); //將x堆結點加入y結點之前(迴圈連結串列中) void FibNodeAdd(FibNode * x, FibNode * y); //初始化一個空的Fibonacci Heap FibHeap * FibHeapMake() ; //初始化結點x FibNode * FibHeapNodeMake(); //堆結點x插入fibonacci heap中 void FibHeapInsert(FibHeap * heap, FibNode * x); //將陣列內的值插入Fibonacci Heap void FibHeapInsertKeys(FibHeap * heap, int keys[], int keyNum); //將值插入Fibonacci Heap static void FibHeapInsertKey(FibHeap * heap, node key); //抽取最小結點 FibNode * FibHeapExtractMin(FibHeap * heap); //合併左右相同度數的二項樹 void FibHeapConsolidate(FibHeap * heap); //將x根結點連結到y根結點 void FibHeapLink(FibHeap * heap, FibNode * x, FibNode *y); //開闢FibHeapConsolidate函式雜湊所用空間 static void FibHeapConsMake(FibHeap * heap); //將堆的最小結點移出,並指向其有兄弟 static FibNode *FibHeapMinRemove(FibHeap * heap); //減小一個關鍵字 void FibHeapDecrease(FibHeap * heap, FibNode * x, node key); //切斷x與父節點y之間的連結,使x成為一個根 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, node key); //被FibHeapSearch呼叫 static FibNode * FibNodeSearch(FibNode * x, node key); //銷燬堆 void FibHeapDestory(FibHeap * heap); //被FibHeapDestory呼叫 static void FibNodeDestory(FibNode * x); //輸出列印堆 static void FibHeapPrint(FibHeap * heap); //被FibHeapPrint呼叫 static void FibNodePrint(FibNode * x); /************************************************/ //將x從雙鏈表移除 inline void FibNodeRemove(FibNode * x) { x->left->right = x->right; x->right->left = x->left; } /* 將x堆結點加入y結點之前(迴圈連結串列中) a …… y a …… x …… y */ inline void FibNodeAdd(FibNode * x, FibNode * y) { x->left = y->left; y->left->right = x; x->right = y; y->left = x; } //初始化一個空的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插入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, node 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) { //刪除z的每一個孩子 while (NULL != z->child) { x = z->child; FibNodeRemove(x); if (x->right == x) { z->child = NULL; } else { z->child = x->right; } FibNodeAdd(x, z);//add x to the root list heap 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; int i; FibNode * w = heap->min, * x = NULL, * y = NULL; FibHeapConsMake(heap);//開闢雜湊所用空間 D = heap->maxNumOfDegree + 1; for ( 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) {//根結點key最小 swap(x, y); } FibHeapLink(heap, y, x); *(heap->cons + d) = NULL; d++; } *(heap->cons + d) = x; } heap->min = NULL;//原有根表清除 //將heap->cons中結點都重新加到根表中,且找出最小根 for ( 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); }//if(<) }//if-else(==) }//if(!=) }//for(i) } //將x根結點連結到y根結點 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; } //開闢FibHeapConsolidate函式雜湊所用空間 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->maxNumOfDegree可能被合併,所以要maxNumOfDegree + 1 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, node 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; } } //切斷x與父節點y之間的連結,使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, node key) { return FibNodeSearch(heap->min, key); } //被FibHeapSearch呼叫 static FibNode * FibNodeSearch(FibNode * x, node 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; } //被FibHeapDestory呼叫 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"); }; //被FibHeapPrint呼叫 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); } const int inf=1147483647;; int aaa[20000000+5]; int bbb[20000000+5]; int main() { freopen( "1.in","r",stdin ); freopen( "5.out","w",stdout ); int_MIN.ff=int_MIN.v=int_MIN.x=-1; int i,j; int n,m,x,y; cin>>n; FibHeap * heap = NULL; heap = FibHeapMake(); for (i=1;i<=n;i++) { scanf("%d %d" ,&aaa[i],&bbb[i]); } DWORD dwStartTime = GetTickCount(); for (i=1;i<=n;i++) { FibHeapInsertKey(heap, node(aaa[i],bbb[i])); } cin>>m; for (i=1;i<=m;i++) { FibHeapExtractMin(heap)->key; } cout<<"耗時"<<GetTickCount()-dwStartTime<<"ms"<<endl; return 0; }