左傾堆的實現

介紹

左傾堆,也被稱爲左偏樹、左偏堆、最左堆等。與二叉堆一樣,它也是優先隊列實現的方法。當涉及到對兩個優先隊列的合併時,左傾堆的效率比二叉堆的效率高很多。

左傾堆的結點

template<class T>
class Node{
	public:
		T key;//鍵值 
		int npl;//零路徑長度(Null Path Length) 
		Node *l;//左孩子 
		Node *r;//右孩子 
		Node(T key,Node *l,Node *r):key(key),npl(0),l(l),r(r){}
};

NPL

npl表示零距離長度:某結點到最近的不滿結點的路徑長度,不滿結點是指最多隻有一個孩子的結點。葉結點的npl=0,空結點的npl爲-1。

二叉堆的特點

  • 結點的鍵值小於或等於它的左右孩子結點的鍵值。
  • 結點的左孩子的npl大於等於右孩子的npl
  • 結點的npl等於右孩子的npl+1。

原理

合併操作

  • 空左傾堆與非空左傾堆合併,返回非空左傾堆。
  • 兩個非空左傾堆合併,取較小堆的根結點爲新的根結點,將較小堆的根結點的右孩子和較大堆進行合併,如果新堆的右孩子的npl大於左孩子的npl,則交換左右孩子,新堆的根結點的npl置爲右子堆的npl+1
//合併左傾堆x和左傾堆y 
template<class T>
Node<T>* LeftistHeap<T>::merge(Node<T>* &x,Node<T>* &y)
{
	if(!x) return y;
	if(!y) return x;
	//合併x,y時,將x作爲合併後的樹的根
	if(x->key>y->key)
	  swapNode(x,y);//保證x->key<y->key
	//將x的右孩子和y合併,合併後的樹的根是x的右孩子
	x->r=merge(x->r,y);
	//如果x的左孩子爲空,或者x的左孩子的npl<右孩子的npl,則交換x和y
	if(!x->l||x->l->npl<x->r->npl)
	{
		Node<T> *tmp=x->l;
		x->l=x->r;
		x->r=tmp;
	}
	//設置合併後的新樹的npl
	if(x->r)
	  x->npl=x->r->npl+1; 
	else
	  x->npl=0;
	return x;
}
 
template<class T>
void LeftistHeap<T>::merge(LeftistHeap<T> *other)
{
	root=merge(root,other->root);
}
 
//添加
template<class T>
Node<T>* LeftistHeap<T>::insert(Node<T>* &heap,T key) 
{
	Node<T> *node=new Node<T>(key,NULL,NULL);
	if(node)
	  return merge(root,node);
	else
	  return heap;  
}
 
template<class T>
void LeftistHeap<T>::insert(T key)
{
	root=insert(root,key);
}

刪除操作

刪除操作只在根結點出進行

//刪除根結點
template<class T>
Node<T>* LeftistHeap<T>::remove(Node<T>* &heap)
{
	if(!heap) return NULL;
	Node<T> *l=heap->l;
	Node<T> *r=heap->r;
	delete heap;//刪除根結點
	return merge(l,r);//返回左右子樹合併後的新樹 
}
 
template<class T>
void LeftistHeap<T>::remove()
{
	root=remove(root);
} 

代碼實現(C++)

#include<iostream>
#include<algorithm>
 
using namespace std;
 
template<class T>
class Node{
	public:
		T key;//鍵值 
		int npl;//零路徑長度(Null Path Length) 
		Node *l;//左孩子 
		Node *r;//右孩子 
		Node(T key,Node *l,Node *r):key(key),npl(0),l(l),r(r){}
};
 
template<class T>
class LeftistHeap{
	private:
		Node<T> *root;
	public:
		LeftistHeap();
		~LeftistHeap();
		void preOrder();//前序遍歷 
		void inOrder();//中序遍歷 
		void postOrder();//後序遍歷 
		void merge(LeftistHeap<T> *other);//合併 
		void insert(T key);//將鍵值爲key的結點插入左傾堆 
		void remove();//刪除根結點結點 
		void destroy();//銷燬左傾堆 
		void print();//打印左傾堆 
		
	private:
		void preOrder(Node<T> *heap);//前序遍歷
		void inOrder(Node<T> *heap);//中序遍歷 
		void postOrder(Node<T> *heap);//後序遍歷 
		void swapNode(Node<T>* &x,Node<T>* &y);//交換結點 
		Node<T>* merge(Node<T>* &x,Node<T>* &y);//合併
		Node<T>* insert(Node<T>* &heap,T key);//將鍵值爲key的結點插入左傾堆 
		Node<T>* remove(Node<T>* &heap);//刪除根結點
		void destroy(Node<T>* &heap);//銷燬左傾堆 
		void print(Node<T>* heap,T key,int child);//打印左傾堆 
};
 
//構造函數
template<class T>
LeftistHeap<T>::LeftistHeap()
{
	root=NULL;
}
 
//析構函數
template<class T>
LeftistHeap<T>::~LeftistHeap()
{
	destroy(root);
} 
 
//前序遍歷
template<class T>
void LeftistHeap<T>::preOrder(Node<T> *tree)
{
	if(tree)
	{
		cout<<tree->key<<" ";
		preOrder(tree->l);
		preOrder(tree->r); 
	}
} 
 
template<class T>
void LeftistHeap<T>::preOrder()
{
	preOrder(root);
}
 
//中序遍歷 
template<class T>
void LeftistHeap<T>::inOrder(Node<T> *tree)
{
	if(tree)
	{
		inOrder(tree->l);
		cout<<tree->key<<" ";
		inOrder(tree->r);
	}
}
 
template<class T>
void LeftistHeap<T>::inOrder()
{
	inOrder(root);
}
 
//後序遍歷
template<class T>
void LeftistHeap<T>::postOrder(Node<T> *tree)
{
	if(tree)
	{
		postOrder(tree->l);
		postOrder(tree->r);
		cout<<tree->key<<" ";
	}
}
 
template<class T>
void LeftistHeap<T>::postOrder()
{
	postOrder(root);
}
 
//交換兩個結點的內容
template<class T>
void LeftistHeap<T>::swapNode(Node<T>* &x,Node<T>* &y)
{
	Node<T> *tmp=x;
	x=y;
	y=tmp;
} 
 
//合併左傾堆x和左傾堆y 
template<class T>
Node<T>* LeftistHeap<T>::merge(Node<T>* &x,Node<T>* &y)
{
	if(!x) return y;
	if(!y) return x;
	//合併x,y時,將x作爲合併後的樹的根
	if(x->key>y->key)
	  swapNode(x,y);//保證x->key<y->key
	//將x的右孩子和y合併,合併後的樹的根是x的右孩子
	x->r=merge(x->r,y);
	//如果x的左孩子爲空,或者x的左孩子的npl<右孩子的npl,則交換x和y
	if(!x->l||x->l->npl<x->r->npl)
	{
		Node<T> *tmp=x->l;
		x->l=x->r;
		x->r=tmp;
	}
	//設置合併後的新樹的npl
	if(x->r)
	  x->npl=x->r->npl+1; 
	else
	  x->npl=0;
	return x;
}
 
template<class T>
void LeftistHeap<T>::merge(LeftistHeap<T> *other)
{
	root=merge(root,other->root);
}
 
//添加
template<class T>
Node<T>* LeftistHeap<T>::insert(Node<T>* &heap,T key) 
{
	Node<T> *node=new Node<T>(key,NULL,NULL);
	if(node)
	  return merge(root,node);
	else
	  return heap;  
}
 
template<class T>
void LeftistHeap<T>::insert(T key)
{
	root=insert(root,key);
}
 
 
//刪除根結點
template<class T>
Node<T>* LeftistHeap<T>::remove(Node<T>* &heap)
{
	if(!heap) return NULL;
	Node<T> *l=heap->l;
	Node<T> *r=heap->r;
	delete heap;//刪除根結點
	return merge(l,r);//返回左右子樹合併後的新樹 
}
 
template<class T>
void LeftistHeap<T>::remove()
{
	root=remove(root);
} 
 
//銷燬左傾堆 
template<class T>
void LeftistHeap<T>::destroy(Node<T>* &tree)
{
	if(tree)
	{
		destroy(tree->l);
		destroy(tree->r);
		delete tree;
	}
} 
 
template<class T>
void LeftistHeap<T>::destroy()
{
	destroy(root);
}
 
template<class T>
void LeftistHeap<T>::print(Node<T> *tree,T key,int child)
{
	if(tree)
	{
		if(child==0)
		  cout<<tree->key<<"("<<tree->npl<<")"<<" is root"<<endl;
		else
		  cout<<tree->key<<"("<<tree->npl<<")"<<" is "<<key<<"'s "<<(child==1?"left child":"right child")<<endl;
		print(tree->l,tree->key,1);
		print(tree->r,tree->key,-1);
	}
}
 
template<class T>
void LeftistHeap<T>::print()
{
	if(root) print(root,root->key,0);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章