左式堆 斜堆

左式堆

第1,左式堆以二叉树的形式构建。

第2,左式堆的任意结点的值比其子树任意结点值均小(最小堆的特性)。但左式堆不是一棵完全二叉树,而是一棵不平衡的树。

第3,NPL是 null path length 的缩写,指的是从该结点到达一个没有两个孩子的结点(一个或无孩子)的最短距离,NULL的Npl为-1。左式堆左儿子的NPL大于等于

          右儿子的 NPL,即左式堆是向左增加深度。容易得出,任意结点的Npl是它右儿子的NLP+1。


源代码:

.h

struct Node
{
	Node *left;
	Node *right;
	int  data;
	int  npl;
};

class LeftHeap
{
	public:
		LeftHeap();
		~LeftHeap();
		
		void Insert(int data);
		int  Delete();
		int  GetMin() const;
		bool IsEmpty() const;
		
		
	private:

		Node *_leftHeap;
		
		Node* _Merge(Node* h1, Node* h2);
		Node* _MergeImp(Node* h1, Node* h2);
		void  _SwapChildren(Node* root);
};
.cpp

LeftHeap::LeftHeap()
{
	_leftHeap = NULL;
}

LeftHeap::~LeftHeap()
{
	while(IsEmpty() == false)
	{
		Delete();
	}
}

void LeftHeap::Insert(int data)
{
	Node *node = new Node;
	node->data = data;
	node->left = node->right = NULL;
	node->npl  = 0;
	
	_leftHeap = _Merge(_leftHeap, node);
	
}

int  LeftHeap::Delete()
{
	
	int data = _leftHeap->data;
	
	Node *left  = _leftHeap->left;
	Node *right = _leftHeap->right;
	
	delete _leftHeap;
	_leftHeap = _Merge(left, right);
	
	return data;
}

int  LeftHeap::GetMin() const
{
	return _leftHeap->data;
}
 
bool LeftHeap::IsEmpty() const
{
	return (_leftHeap == NULL);
}

void  LeftHeap::_SwapChildren(Node* root)
{
	Node *tmp   = root->left;
	root->left  = root->right;
	root->right = tmp;
}

Node* LeftHeap::_Merge(Node* h1, Node* h2)
{
	if(h1 == NULL)
		return h2;
	if(h2 == NULL)
		return h1;
		
	if(h1->data < h2->data)
		return _MergeImp(h1, h2);
	else
		return _MergeImp(h2, h1);
}

Node* LeftHeap::_MergeImp(Node* h1, Node* h2)
{
	if(h1->left == NULL)
	{
		h1->left = h2;
	}
	else
	{
		h1->right = _Merge(h1->right, h2);
		if(h1->left->npl < h1->right->npl)
			_SwapChildren(h1);
		
		h1->npl = h1->right->npl + 1;
	}
	return h1;
}


斜堆

       斜堆是左式堆的自动调节形式。

       由于左式堆的合并都是沿着最右路径进行合并的,经过合并之后,新斜堆的最右路径长度必然增加,这会影响下一次合并的效率。所以左式堆在进行合并的同时,

       检查最右路径节点的距离(NPL),并通过交换左右子树,使整棵树的最右路径长度非常小。然而斜堆不记录节点的距离,在操作时,从下往上,沿着合并的路径,

       在每个节点处都交换左右子树。通过不断交换左右子树,斜堆把最右路径甩向左边了。    

.h

struct Node
{
	Node *left;
	Node *right;
	int  data;
};

class LeftHeap
{
	public:
		LeftHeap();
		~LeftHeap();
		
		void Insert(int data);
		int  Delete();
		int  GetMin() const;
		bool IsEmpty() const;
		
		
	private:

		Node *_leftHeap;
		
		Node* _Merge(Node* h1, Node* h2);
		Node* _MergeImp(Node* h1, Node* h2);
		void  _SwapChildren(Node* root);
};

.cpp

#define NULL 0

LeftHeap::LeftHeap()
{
	_leftHeap = NULL;
}

LeftHeap::~LeftHeap()
{
	while(IsEmpty() == false)
	{
		Delete();
	}
}

void LeftHeap::Insert(int data)
{
	Node *node = new Node;
	node->data = data;
	node->left = node->right = NULL;
	
	_leftHeap = _Merge(_leftHeap, node);
	
}

int  LeftHeap::Delete()
{
	
	int data = _leftHeap->data;
	
	Node *left  = _leftHeap->left;
	Node *right = _leftHeap->right;
	
	delete _leftHeap;
	_leftHeap = _Merge(left, right);
	
	return data;
}

int  LeftHeap::GetMin() const
{
	return _leftHeap->data;
}
 
bool LeftHeap::IsEmpty() const
{
	return (_leftHeap == NULL);
}

void  LeftHeap::_SwapChildren(Node* root)
{
	Node *tmp   = root->left;
	root->left  = root->right;
	root->right = tmp;
}

Node* LeftHeap::_Merge(Node* h1, Node* h2)
{
	if(h1 == NULL)
		return h2;
	if(h2 == NULL)
		return h1;
		
	if(h1->data < h2->data)
		return _MergeImp(h1, h2);
	else
		return _MergeImp(h2, h1);
}

Node* LeftHeap::_MergeImp(Node* h1, Node* h2)
{
	if(h1->left == NULL)
	{
		h1->left = h2;
	}
	else
	{
		h1->right = _Merge(h1->right, h2);
		_SwapChildren(h1);
		
	}
	return h1;
}		
	


总结:虽然二叉堆简单,但不适合合并操作,而左式堆和斜堆高效支持合并操作。

      



你可能感兴趣的:(左式堆 斜堆)