DateStructure 练习 Fibonacci Heap实现

//fheap.h
//author:aether
//date:2012年12月17日
#ifndef FHEAP_H
#define FHEAP_H
#include 
#include 
//Remark:斐波那契堆不一定是二项树,而是最小堆有序树
namespace fib
{

#define nil 0
#define null -1

	class FibHeap;
	class Node
	{
	public:
		friend class FibHeap;
		Node(int k = 0):p(nil),c(nil),left(nil),right(nil),key(k),degree(0),mark(false){}
	private:
		Node *p;//指向父节点指针
		Node *c;//指向任意子女的指针
		Node *left;//指向左兄弟
		Node *right;//指向右兄弟
		int key;//关键字 
		size_t degree;//度数
		bool mark;//标记值
	};

	class FibHeap
	{
	public:
		FibHeap();
		void insert(Node *x);
		void heapUnion(FibHeap *fh);
		Node* extractMin();
		void decreaseKey(Node *x,int newKey);
		void del(Node *x);
	private:
		void consolidDate();
		void link(Node *x,Node *y);
		void cut(Node *x,Node *y);
		void cascadingCut(Node *y);
		size_t num;//节点个数
		Node *min;//最小节点
	};
}
#endif
//fheap.cpp
//author:aether
//date:2012年12月17日
#include "fheap.h"
namespace fib
{
	FibHeap::FibHeap()
	{
		num = 0;
		min = nil;
	}
	void FibHeap::insert(Node *x)
	{
		x->left = x;
		x->right = x;
		if(min == nil)
			min = x;
		else
		{
			Node *left = min->left;
			min->left = x;
			left->right = x;
			x->left = left;
			x->right = min;
		}
		if(min != nil && x->key < min->key)
			min = x;
		num += 1;
	}
	void FibHeap::heapUnion(FibHeap *fh)
	{
		Node *x = fh->min;
		if(x == nil || x == min)
			return;
		Node *a = x->left;
		Node *b = x->right;
		x->left = nil;
		x->right = nil;
		a->right = nil;
		b->left = nil;
		insert(x);
		if(a != x)
		{
			while( a != nil)
			{
				Node *b = a->left;
				insert(a);
				a = b;
			}
		}
		if(min == nil || (x->key < min->key))
			min = x;
		fh->min = nil;
		fh->num = 0;
	}
	Node* FibHeap::extractMin()//真正进行合并的操作
	{
		Node *z = min;
		if(z != nil)
		{
			//步骤①,剪短最小节点和子节点之间的关系,并且把子节点们放到根列表中
			Node *child = z->c;
			z->c = nil;
			if(child != nil)
			{
				child->p = nil;
				Node *left = child->left;
				Node *right = child->right;
				child->left = nil;
				child->right = nil;
				insert(child);
				if(left != child)
				{
					while(left != nil)
					{
						Node *b = left->left;
						left->p = nil;
						insert(left);
						left = b;
					}
				}
			}
			//步骤二,去除z节点
			Node *left = z->left;
			Node *right = z->right;
			left->right = right;
			right->left = left;
			if(z == z->right)
				min = nil;
			else
			{
				min = z->right;
				z->right = nil;
				z->left = nil;
				consolidDate();
			}
			num -= 1;
		}
		return z;
	}
	void FibHeap::decreaseKey(Node *x,int newKey)
	{
		if(x->key < newKey)
			return;
		x->key = newKey;
		Node *y = x->p;
		if(y != nil && y->key > x->key)
		{
			cut(x,y);
			cascadingCut(y);
		}
		if(x->key < min->key)
			min = x;
	}
	void FibHeap::del(Node *x)
	{
		decreaseKey(x,null);
		extractMin();
	}
	void FibHeap::consolidDate()
	{
		size_t size = size_t(sqrt(float(num)))+1;
		Node **A = static_cast(::operator new[](sizeof(Node*)*size));
		for(size_t i = 0; i != size;++i)
			A[i] = nil;
		Node *w = min;
		Node *end = w->left;
		bool flag = true;
		while(flag)
		{
			if(w == end)
				flag = false;
			Node *x = w;
			size_t d = x->degree;
			while(A[d] != nil)
			{
				Node *y = A[d];
				if(x->key > y->key)
				{
					int temp = x->key;
					x->key = y->key;
					y->key = temp;
				}
				link(x,y);
				A[d] = nil;
				if(d+1 != size)
					d += 1;
				else
					break;
			}
			A[d] = x;
			w = w->right;
		}
		min = w;
		for(size_t i = 0; i != size; ++i)
		{
			if(A[i] != nil && min->key > A[i]->key)
				min = A[i];
		}
		::operator delete[](static_cast(A));
	}
	void FibHeap::link(Node *x,Node *y)//consolidDate辅助函数,将y从根列表移除,合并到x上
	{
		Node *left = y->left;
		Node *right = y->right;
		left->right = right;
		right->left = left;
		y->left = y;
		y->right = y;
		Node *childs = x->c;
		x->c = y;
		y->p = x;
		if(childs != nil)
		{
			Node *b = childs->left;
			childs->left = y;
			b->right = y;
			y->right = childs;
			y->left = b;
		}
		x->degree += 1;
		y->mark = false;
	}
	void FibHeap::cut(Node *x,Node *y)
	{
		Node *left = x->left;
		Node *parent = x->p;
		Node *right = x->right;
		left->right = right;
		right->left = left;
		x->left = nil;
		x->right = nil;
		x->p = nil;
		if(parent->c == x && left != x)
		{
			parent->c = left;
			y->degree -= 1;
		}
		if(parent->c == x && left == x)
			parent->c = nil;
		insert(x);
		num -= 1;
		x->mark = false;
		
	}
	void FibHeap::cascadingCut(Node *y)
	{
		Node *z = y->p;
		if(z != nil)
		{
			if(y->mark == false)
				y->mark =true;
			else
			{
				cut(y,z);
				cascadingCut(z);
			}
		}
	}
}

第一篇博文,有很多很生疏的地方,姑且自己娱乐自己吧。

实现的也有不少问题,算法导论上对于斐波那契堆的应用讲得并不多,有时候都会想,这么纠结的玩意,到哪去应用呢?

有些操作,书上都是随意带过了,但是自己实现的时候还是出现了许多问题,如果大神路过,请轻喷。

同二项堆不同,其中的树并不一定是二项树,而是最小堆有序树。

这是一种基于平摊分析的产物,尽可能将一些操作延后至extractMin操作。

复杂度高,但是平摊时间界却很好,对它的使用有一定取舍,可以适应于一些应用。

两天时间,写了两遍,对自己很不满意。

后续有时间,肯定要优化下,不过现在,脑子已经快罢工了。

贴上最后的main。

#include "fheap.h"
#include 
using fib::FibHeap;
using fib::Node;
void main()
{
	FibHeap fh;
	FibHeap fh2;
	Node n1(10);
	Node n2(9);
	Node n3(8);
	Node n4(7);
	Node n5(6);
	Node n6(5);
	fh.insert(&n1);
	fh.insert(&n2);
	fh.insert(&n3);
	fh2.insert(&n4);
	fh2.insert(&n5);
	fh2.insert(&n6);
	fh.heapUnion(&fh2);
	Node *min = fh.extractMin();
	fh.decreaseKey(&n1,2);
	fh.del(&n1);
	system("Pause");
}


在实现过程中,由于应用到了sqrt,突然脑袋扯了,想起一种手动开根方法,比较固执,不想去网上找方法,最后实现了半个多小时,无果而终,没想到网上的方法很简单很简单,也一起分享一下。
float mySqrt(int x)
{
	//第一步寻找近似值
	int y = 0;
	while( (y+1)*(y+1) < x)
		++y;
	if( (y+1)*(y+1) == x)
		return float(y+1);
	float z = float(y);
	size_t num = 3;//计算次数
	while(num--)
	{
		z = (z+x/z)/2;
	}
	return z;
}
这种方法的原理通过逐步进行近似计算,取到想要的精度即可。

例如对于5,可以找到第一个近似值2^2,不大于5。

然后通过 z = (z+x/z)/2的方法,一直进行计算,z是上一步的近似计算值(貌似就是牛顿迭代的变形?)

还有诸如二分法之类的也可以,网上瞥到了牛顿迭代法(其实我只知道名字,没细看),等等等等。

只是一个小插曲,以后有机会可以继续研究。


你可能感兴趣的:(Date,Structure)