斐波那契堆 插入、 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;
}








你可能感兴趣的:(斐波那契堆 插入、 Extract-Min(查找+删除)效率与 STL优先队列对比)