二叉查找树【数据结构】

                                                二叉查找树

一、介绍

二叉查找树(Binary Search Tree),也被称作二叉搜索树。设x是二叉查找树中的任意一个结点,则x的键值大于等于它的左子树中任意一个结点的键值,小于等于它的右子树中任意一个结点的键值。

二、原理

1、结点的前驱和后继

结点的前驱:二叉树中键值小于该结点的最大结点。
结点的后继:二叉树中键值大于该结点的最小结点

查找前驱结点的方法:
如果x存在左孩子,则x的前驱结点为以其左孩子为根的子树的最大结点  
如果x不存在左孩子:
1>x是一个右孩子,前驱结点就是它的父结点
2>x是一个左孩子,查找x的最低父结点,并且x位于该父结点的右子树中,前驱结点就是这个父结点 

查找后继结点的方法
如果x存在右孩子,则x的后继结点为以其右孩子为根的子树的最小结点  
如果x不存在右孩子:
1>x是一个左孩子,后继结点就是它的父结点
2>x是一个右孩子,查找x的最低父结点,并且x位于该父结点的左子树中,后继结点就是这个父结点 

2、插入结点

插入操作均是在叶结点处进行的,因此,只要按照插入结点的值找到相应的叶结点就OK了,程序中x、y表示两个结点,x初始化为根结点,通过这两个变量寻找新结点 z 的插入位置,根据x结点的值与z结点的值的比较结果选择对应的路径,直到x等于NULL,此时y就是我们想寻找的叶节点,这时只需将y和z链接起来就行。

//插入键值为key的结点(内部接口)
template <class T>
void BSTree<T>::insert(Node<T>* &tree,Node<T> *z)
{
	Node<T> *y=NULL;
	Node<T> *x=tree;
	//寻找z的插入位置 
	while(x)
	{
		y=x;
		if(z->key<x->key)
		  x=x->l;
		else
		  x=x->r;
	}
	if(!y)//树为空 
	  tree=z;
	else
	{
		z->p=y;//z的父结点为y 
		if(z->key<y->key)//z是y的左孩子 
		  y->l=z;
		else
		  y->r=z;//z是y的右孩子 
	}
}

//插入键值为key的结点(外部接口)
template<class T>
void BSTree<T>::insert(T key)
{
	Node<T> *z=new Node<T>(key,NULL,NULL,NULL);
	if(z) insert(root,z);
} 

3、删除结点

根据键值进行删除操作,删除结点后还要维持二叉查找树的特点,真正被删除的结点其实是这一类结点:最多只有一个孩子结点,删除这类结点非常简单,只需要将它的孩子结点和它的父结点进行链接,再把自己释放掉就行。当被删除结点就是这类结点时,直接按上面的操作进行即可。当被删除结点不是这类结点时,就需要找到一个代替的点,这就是该结点的后继结点,将该结点的键值变为后继结点的键值,然后删除后继结点即可,容易知道后继结点是上面描述的那类结点,因此照着描述进行操作即可。

//删除结点(内部接口)
template<class T>
Node<T>* BSTree<T>::remove(Node<T>* &tree,Node<T> *z)
{
	Node<T> *x=NULL,*y=NULL;//y是真正要被删除的结点,x是y的孩子结点 
	if(z->l&&z->r)//如果z的左右孩子都在,y就等于z的后继结点 
	  y=successor(z); 
	else//否则,y=z 
	  y=z;
	
	//此时对于 y有3种情况  1.只存在左孩子  2.只存在右孩子  3.不存在孩子 
	if(y->l)//情况一 
	  x=y->l; 
	else //情况二、三 
	  x=y->r;
	  
	if(x) x->p=y->p;//如果y存在孩子结点,那么就将孩子结点的父结点变为y的父结点 
	
	if(!y->p) 
	  tree=x;//如果y是根结点,就让根结点变为x
	else if(y==y->p->l)
	  y->p->l=x;
	else
	  y->p->r=x;
	if(y!=z)
	  z->key=y->key; 
	return y;
}
 
//删除结点,并返回结点(外部接口)
template<class T>
void BSTree<T>::remove(T key)
{
	Node<T> *z,*node;
	if((z=search(root,key)))//查找到键值为key的结点 
	{
		if((node=remove(root,z)))//删除成功 
		  delete node;
	}
}

三、C++实现

注意:程序使用了内部接口和外部接口,这样做主要是因为数据成员 root 为私有变量

#include<iostream>

using namespace std;

template<class T>
class Node{
	public:
		T key;//键值 
		Node *p;//父节点
		Node *l;//左孩子 
		Node *r;//右孩子 
		Node(T key,Node *p,Node *l,Node *r):key(key),p(p),l(l),r(r){} 
}; 

template<class T>
class BSTree{
	private:
		Node<T> *root;//根结点
	public:
		BSTree();
		~BSTree();
		void preOrder();//前序遍历 
		void inOrder();//中序遍历 
		void postOrder(); //后序遍历 
		
		Node<T>* search(T key); //查找二叉树中键值为key的结点 (递归实现)
		Node<T>* iterativeSearch(T key); //查找二叉树中键值为key的结点(非递归实现)
		
		T minimum();//查找最小结点:返回最小结点的键值
		T maximum();//查找最大结点:返回最大结点的键值
		
		//查找结点x的前驱结点,即查找二叉树中键值小于该结点的最大结点
		Node<T>* predecessor(Node<T> *x); 
		//查找结点x的后继结点,即查找二叉树中键值大于该结点的最小结点
		Node<T>* successor(Node<T> *x);
		
		void insert(T key);//将键值为key的结点插入到二叉树中
		void remove(T key);//删除键值为key的结点 
		
		void destroy();//销毁二叉树
		void print();//打印二叉树
		
	private:
		void preOrder(Node<T> *tree);//前序遍历
		void inOrder(Node<T> *tree);//中序遍历
		void postOrder(Node<T> *tree);//后序遍历
		Node<T>* search(Node<T>* x,T key);//查找键值为key的结点(递归实现)
		Node<T>* iterativeSearch(Node<T>* x,T key);//查找键值为key的结点(非递归实现)
		
		//查找最小结点:返回tree为根结点的二叉树的最小结点 
		Node<T>* minimum(Node<T>* tree);
		//查找最大结点:返回tree为根节点的二叉树的最大结点 
		Node<T>* maximum(Node<T>* tree);
		
		void insert(Node<T>* &tree,Node<T> *z);//插入结点z
		Node<T>* remove(Node<T>* &tree,Node<T> *z);//删除并返回结点z
		
		void destroy(Node<T>* &tree);//销毁二叉树
		void print(Node<T>* tree,T key,int direction);//打印二叉树 
};

//构造函数
template<class T>
BSTree<T>::BSTree()
{
	root=NULL;
} 

//析构函数
template<class T>
BSTree<T>::~BSTree()
{
	destroy();
} 

//前序遍历(内部接口) 
template<class T>
void BSTree<T>::preOrder(Node<T>* tree)
{
	if(tree)
	{
		cout<<tree->key<<" ";
		preOrder(tree->l);
		preOrder(tree->r); 
	}
}

//前序遍历(外部接口) 
template<class T>
void BSTree<T>::preOrder()
{
	preOrder(root);
}

//中序遍历(内部接口) 
template<class T>
void BSTree<T>::inOrder(Node<T>* tree)
{
	if(tree)
	{
		inOrder(tree->l);
		cout<<tree->key<<" ";
		inOrder(tree->r);
	}
}

//中序遍历(外部接口) 
template<class T>
void BSTree<T>::inOrder()
{
	inOrder(root);
}

//后序遍历(内部接口) 
template<class T>
void BSTree<T>::postOrder(Node<T> *tree)
{
	if(tree)
	{
		postOrder(tree->l);
		postOrder(tree->r);
		cout<<tree->key<<" ";
	}
}

//后序遍历(外部接口) 
template<class T>
void BSTree<T>::postOrder()
{
	postOrder(root);
}


//查找键值为key的结点(递归实现) 内部接口 
template<class T>
Node<T>* BSTree<T>::search(Node<T>* x,T key)
{
	if(!x||x->key==key)
	  return x;
	if(key<x->key)
	  return search(x->l,key);
	else
	  return search(x->r,key);
}

//查找键值为key的结点(递归实现) 外部接口 
template<class T>
Node<T>* BSTree<T>::search(T key)
{
	search(root,key);
}


//查找键值为key的结点(非递归实现) 内部接口 
template<class T>
Node<T>* BSTree<T>::iterativeSearch(Node<T>* x,T key)
{
	while(x)
	{
		if(key==x->key)
		  return x;
		else if(key<x->key)
		  x=x->l;
		else
		  x=x->r;
	}
	return x;
}

//查找键值为key的结点(非递归实现) 外部接口
template<class T>
Node<T>* BSTree<T>::iterativeSearch(T key)
{
	iterativeSearch(root,key);
}

//查找最大值(内部接口) 
template<class T>
Node<T>* BSTree<T>::maximum(Node<T>* tree)
{
	if(!tree) return NULL;
	while(tree->r) tree=tree->r;
	return tree;
} 
//查找最大值(外部接口)
template<class T>
T BSTree<T>::maximum()
{
	Node<T>* p=maximum(root);
	if(p)
	  return p->key;
	else
	  return (T)NULL;
} 

//查找最小值(内部接口)
template<class T>
Node<T>* BSTree<T>::minimum(Node<T>* tree)
{
	if(!tree) return  NULL;
	while(tree->l) tree=tree->l;
	return tree;
}

//查找最小值(外部接口) 
template<class T>
T BSTree<T>::minimum()
{
	Node<T>* p=minimum(root);
	if(p)
	  return p->key;
	else
	  return (T)NULL;
}

//结点的前驱:该结点的左子树的最大结点
//结点的后继:该结点的右子树的最小结点

//查找结点的前驱结点,即二叉树中键值小于该结点的最大结点
/*
如果x存在左孩子,则x的前驱结点为以其左孩子为根的子树的最大结点  
如果x不存在左孩子:
1>x是一个右孩子,前驱结点就是它的父结点
2>x是一个左孩子,查找x的最低父结点,并且x位于该父结点的右子树中,前驱结点就是这个父结点 
*/
template<class T> 
Node<T>* BSTree<T>::predecessor(Node<T> *x)
{
	if(x->l) return maximum(x->l);
	Node<T>* y=x->p;
	while(y&&(x==y->l))
	{
		x=y;
		y=y->p;
	}
	return y;
} 

//查找结点的后继结点,即二叉树中键值大于该结点的最小结点
/*
如果x存在右孩子,则x的后继结点为以其右孩子为根的子树的最小结点  
如果x不存在右孩子:
1>x是一个左孩子,后继结点就是它的父结点
2>x是一个右孩子,查找x的最低父结点,并且x位于该父结点的左子树中,后继结点就是这个父结点 
*/
template<class T>
Node<T>* BSTree<T>::successor(Node<T> *x)
{
	if(x->r) return maximum(x->r);
	Node<T> *y=x->p;
	while(y&&(x==y->r))
	{
		x=y;
		y=y->p;
	}
	return y;
}
 
//插入键值为key的结点(内部接口)
template <class T>
void BSTree<T>::insert(Node<T>* &tree,Node<T> *z)
{
	Node<T> *y=NULL;
	Node<T> *x=tree;
	//寻找z的插入位置 
	while(x)
	{
		y=x;
		if(z->key<x->key)
		  x=x->l;
		else
		  x=x->r;
	}
	if(!y)//树为空 
	  tree=z;
	else
	{
		z->p=y;//z的父结点为y 
		if(z->key<y->key)//z是y的左孩子 
		  y->l=z;
		else
		  y->r=z;//z是y的右孩子 
	}
}

//插入键值为key的结点(外部接口)
template<class T>
void BSTree<T>::insert(T key)
{
	Node<T> *z=new Node<T>(key,NULL,NULL,NULL);
	if(z) insert(root,z);
} 

//删除结点(内部接口)
template<class T>
Node<T>* BSTree<T>::remove(Node<T>* &tree,Node<T> *z)
{
	Node<T> *x=NULL,*y=NULL;//y是真正要被删除的结点,x是y的孩子结点 
	if(z->l&&z->r)//如果z的左右孩子都在,y就等于z的后继结点 
	  y=successor(z); 
	else//否则,y=z 
	  y=z;
	
	//此时对于 y有3种情况  1.只存在左孩子  2.只存在右孩子  3.不存在孩子 
	if(y->l)//情况一 
	  x=y->l; 
	else //情况二、三 
	  x=y->r;
	  
	if(x) x->p=y->p;//如果y存在孩子结点,那么就将孩子结点的父结点变为y的父结点 
	
	if(!y->p) 
	  tree=x;//如果y是根结点,就让根结点变为x
	else if(y==y->p->l)
	  y->p->l=x;
	else
	  y->p->r=x;
	if(y!=z)
	  z->key=y->key; 
	return y;
}
 
//删除结点,并返回结点(外部接口)
template<class T>
void BSTree<T>::remove(T key)
{
	Node<T> *z,*node;
	if((z=search(root,key)))//查找到键值为key的结点 
	{
		if((node=remove(root,z)))//删除成功 
		  delete node;
	}
}

//打印(内部接口) 
template<class T>
void BSTree<T>::print(Node<T> *tree,T key,int direction)
{
	if(tree)
	{
		if(direction==0)
		  cout<<tree->key<<" is root"<<endl;
		else
		  cout<<tree->key<<" is "<<key<<"'s"<<(direction==1?"right child":"left child")<<endl;
		print(tree->l,tree->key,-1);
		print(tree->r,tree->key,1);  
	}
}

//打印(外部接口) 
template<class T>
void BSTree<T>::print()
{
	if(root) print(root,root->key,0);
}

//销毁(内部接口)
template<class T>
void BSTree<T>::destroy(Node<T>* &tree)
{
	if(tree)
	{
		if(tree->l) destroy(tree->l);
		if(tree->r) destroy(tree->r);
		delete tree;
		tree=NULL;
	}
}

//外部接口
template<class T>
void BSTree<T>::destroy()
{
	destroy(root);
}

猜你喜欢

转载自blog.csdn.net/SongBai1997/article/details/85200246