1. 程式人生 > >斐波那契堆 插入、 Extract-Min(查詢+刪除)效率與 STL優先佇列對比

斐波那契堆 插入、 Extract-Min(查詢+刪除)效率與 STL優先佇列對比

插入 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;
}