二分搜索树,堆,及优先队列

在描述二叉树,堆,优先队列之前之前,有必要介绍节点和向量,在二叉树,队,优先队列中会有使用:

二叉树可以用链接在一起的一个个节点描述,每个节点包含一个数据元素和指向左右子树的指针,可以用类定义节点(结构体也可以):

template<typename T>
class treenode{
public:
T ele;
treenode*left;
treenode*right;
treenode(){ele=0;left=NULL;right=NULL;}
treenode(T el){ele=el;left=NULL;right=NULL;}
};

堆和优先队列虽然都是二叉树结构,也可以由二叉树表示,但是不及数组或者向量表示,尤其是面对数目未定增删多的时候,向量首选:

template<typename T>
class vecs{
private:
 T *ele;
 int size;
int cap;
public:
	vecs<T>(){size=0;cap=16;ele=new T(cap);}
	void sure(){if(size>cap)
	{T *old=ele;
	cap=2*size;
	ele=new T(cap);
	for(int i=0;i<size;i++)
	  ele[i]=old[i];
	delete old;}}
	void push_back(T ele1){
		sure();
	ele[size++]=ele1;}
	void pop_back(){
	if(size==0) throw runtime_error("empty");
	--size;}
	void clear(){
		while(size!=0){
		pop_back();}}
	int getsize(){return size;}
	bool empty(){return (size==0);}
	T at(int index){
	if(index<0||index>cap)throw runtime_error("empty");
	return ele[index];}
	T&operator[](int index){
	if(index<0||index>cap)throw runtime_error("empty");
	return ele[index];}
	void swap(vecs&v1){
int len=v1.getsize();
	if(len>=size){
		T *p=new T[len];
for(int i=0;i<size;i++)
{p[i]=ele[i];}
clear();
for(int i=0;i<len;i++)
	push_back(v1.at(i));
	v1.clear();
for(int i=0;i<len;i++)
{v1.push_back(p[i]);}}
	else{
	T *p=new T[size];
for(int i=0;i<size;i++)
{p[i]=ele[i];}
clear();
for(int i=0;i<len;i++)
{ele[i]=v1.at(i);}
v1.clear();
for(int i=0;i<size;i++)
{v1.push_back(p[i]);}
	}
}
};
常用的二叉树是二叉搜索树,即:任意节点大于其左节点小于其右节点:涉及到插入,前序,后序,中序操作:

template<typename T>
class bitree{
private:treenode<T>*root;
		int size;
         void inorder(treenode<T>*root);
		 void preorder(treenode<T>*root);
		 void postorder(treenode<T>*root);
public:
	bitree(){root=NULL;size=0;}
	bitree(T ele[],int size);
	bool insert(T ele);
    void inorder();
void preorder();
void postorder();
};
template<typename T>
bitree<T>::bitree(T ele[],int size){
root=new treenode<T>(ele[0]);
this->size=size;;
for(int i=0;i<size;i++)
  insert(ele[i]);}
template<typename T>
bool bitree<T>::insert(T ele){
if(root==NULL) root=new treenode<T>(ele);
else{
treenode<T>*parent=NULL;
treenode<T>*p=root;
while(p!=NULL){
	if(ele<p->ele){parent=p;
	p=p->left;}//新元素小于父节点,则做父节点左孩纸
	else if(ele>p->ele){parent=p;p=p->right;}//新元素大于父节点,则做父节点右边孩纸
	else return false;}
	if(ele<parent->ele)parent->left=new treenode<T>(ele);
	else parent->right=new treenode<T>(ele);
}
size++;
return true;}

template<typename T>
void bitree<T>::inorder(){
inorder(root);}
template<typename T>
void bitree<T>::inorder(treenode<T>*root){
if(root==NULL) return;
else{
	inorder(root->left);
	cout<<root->ele<<" ";
	inorder(root->right);
	}
}//中序遍历,递归
template<typename T>
void bitree<T>::preorder(){
preorder(root);}
template<typename T>
void bitree<T>::preorder(treenode<T>*root){
	if(root==NULL)return;
	else{
	cout<<root->ele<<" ";
	preorder(root->left);
	preorder(root->right);}}//前序遍历
template<typename T>
void bitree<T>::postorder(){
postorder(root);}
template<typename T>
void bitree<T>::postorder(treenode<T>*root){
if(root==NULL) return;
else{postorder(root->left);
postorder(root->right);
cout<<root->ele<<" ";
}}//后序
二叉树插入:若二叉树为空,直接创建一个root节点;若非空,则进行比较:当插入节点小于父节点时候,则作为左节点,反之则是右节点。否则相等时说明二叉树已含此数字不插入;

遍历:通过递归思想,输出父节点,递归左子树和右子树;

堆也是一种二叉树,满足:

是完全二叉树(倒数一层外都是满,最后一层即使不满也是左满);

是满足父节点大于任意子节点,则根节点是最大值;

堆和优先队列虽然都是二叉树结构,也可以由二叉树表示,但是不及数组或者向量表示,尤其是面对数目未定增删多的时候,向量首选:当前节点处于向量或者数组i位置时候,其父节点在(i-1)/2,左右节点在2*i+1,2*i+2位置处。堆的重点在于删除和插入:


template<typename T>
class heap{
private:
vvs<T> vv;
public:
heap();
heap(T ele[],int size);
T remove();
void add(T ele);
int getsi();};
template<typename T>
heap<T>::heap(){}
template<typename T>
heap<T>::heap(T ele[],int size){
for(int i=0;i<size;i++)
  add(ele[i]);}
template<typename T>
T heap<T>::remove(){
	if(vv.getsize()==0) throw runtime_error("empty");
	T tep=vv[0];
	vv[0]=vv[vv.getsize()-1];//change last and first
	vv.pop_back();//delete the root
	int i=0;//root
		while(i<vv.getsize()){
		int le=2*i+1;
		int ri=2*i+2;
		if(le>=vv.getsize())break;//tree is heap
		int max=le;
		if(ri<vv.getsize()){if(vv[max]<vv[ri]) max=ri;}
		if(vv[i]<vv[max]){T t=vv[max];vv[max]=vv[i];vv[i]=t;i=max;//返回下一层
		}
		else break;
	}
		
	return tep;
}
template<typename T>
void heap<T>::add(T ele){
	vv.push_back(ele);//将新节点添加到堆尾
	int i=vv.getsize()-1;
	while(i>0){
	int pa=(i-1)/2;
	if(vv[i]>vv[pa]){T te=vv[i];vv[i]=vv[pa];vv[pa]=te;}
	else break;//now is heap
	i=pa;//返回上一层
	}}
template<typename T>
int heap<T>::getsi(){
	return vv.getsize();}

优先队列不同于普通队列,普通队列FIFO,利用链表即可实现,是线性结构;而优先队列是层次结构,需通过堆实现:最大先出的原则:

template<typename T>
class prique{
private:
heap<T> hea;
public:
	void enque(T ele){hea.add(ele);}
	T deque(){return hea.remove();}//最大先出。满足优先队列定义
	int getsiz(){return hea.getsi();}};
下面给出一个利用优先队列模拟病人排队的例子:

class patient{
private:
	string name;
	int level;
public:
	patient(){};
	patient(string s,int le){
	name=s;level=le;}
	bool operator<(patient&q){
		return (level<q.level);}
bool operator>(patient&q){
		return !(level<q.level);}
		string getname(){return name;}
		int getle(){return level;}};
int main(){
prique<patient> pp;
pp.enque(patient("zhang",2));
pp.enque(patient("zhao",1));
pp.enque(patient("Tim",5));
pp.enque(patient("cindi",7));
while(pp.getsiz()>0){
	patient t=pp.deque();
	cout<<"level:"<<t.getle()<<" the name: "<<t.getname()<<endl;
}
system("pause");
return 0;}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值