二叉查找树

二叉查找树分析与实现

二叉查找树有一下几个特点:

1,左孩子总是小于其父亲节点,右孩子总是大于其父亲节点

2,每颗子树都是一棵二叉查找树

3,通过中序遍历二叉树可以得到一个有序序列

作用:可以用来排序,可以在平均O(lgn)的时间的进行数据的快速查找,二叉查找数具有不稳定性,在建树的时候,有可能这个二叉树只有左子树或右子树,这样这颗二叉树就演化成了一个线性表了,那么他的查找时间复杂度最坏要为O(n),所有就又出现了一种对此树的一种弄个改进相似数据结构-平衡二叉树

基本操作: 建树,遍历,插入节点,删除,还有释放树

二叉查找树的存储结构

typedef struct LNode
{
	int data; //值
	LNode *LChild;	//左孩子
	LNode *RChild;//右孩子
	LNode *Parent;//父节点
} *STree;


注:要父节点的的目的主要是进行删除的时候需要用到父节点

建树和插入:其实就是一个不断的插入操作,每次插入都会新生成一个新的叶子节点

//插入操作
void insert(STree &root,int key){
	LNode *p=(STree)malloc(sizeof(LNode));
	p->data=key;
	p->LChild=p->RChild=p->Parent=NULL;
	if(NULL==root){		//如果树为空,则直接赋给根节点

		root=p;
		return;
	}
	if(NULL==root->LChild&&key<root->data){
	
		root->LChild=p;
		p->Parent=root;
		return;
	}
	if(NULL==root->RChild&&key>=root->data){
	
		root->RChild=p;
		p->Parent=root;
		return ;
	}
	if(root->data>key) 
		insert(root->LChild,key);
	else
		insert(root->RChild,key);
}



查找:查找步骤很简单,从根节点开始,如果此元素大于根节点,怎把指针指向其右孩子,反之则指向其左孩子,然后继续重复上述步骤。

//查找,成功返回1,失败0,用节点引用记录查找成功的节点
int Search(const STree T,STree &p,int n)
{
	if(T&&T->data==n) //如果查找成功
	{
		p=T;
		return 1;
	}
	if(T->LChild&&T->data>n)  Search(T->LChild,p,n);
	else if(T->RChild&&T->data<n) Search(T->RChild,p,n);
	else 
	{
		p=NULL;
		return 0;
	}
}


中序遍历:遍历出的结果是有序的

//中序遍历
void Mid(const STree T)
{
	if(T==NULL)
		return ;
	Mid(T->LChild);
	cout<<T->data<<" ";
	Mid(T->RChild);
}

删除:删除操作稍微麻烦,分几种情况

1,删除节点a为叶子节点,则直接删除

2,删除节点a有一个左孩子或右孩子,则删除此节点,让其左孩子或右孩子的父节点变为被删除节点的父节点

3,删除节点a既有左孩子又有右孩子,这样就不是太简单了,首先我们要明白在中序遍历的时候,一个节点的前驱肯定没有右孩子,后继肯定没有左孩子,我们就找该节点的前驱或后继来替代当前节点,然后a的孩子节点的父节点为a的父节点。

//删除节点
void DeleteBST(STree &root,int n)
{
	//欲删除节点,要找到该节点的位置,及是否有左右孩子
	STree p;								//用来记录查找到要删除的节点的位置和其父节点的位置
	STree k=NULL; //缓冲节点,初始化为NULL是为了安全
	int flag=Search(root,p,n);  //查找删除节点是否存在,如果存在,则返回被删除节点p
	if(flag==0) {
		cout<<"要删除的节点不存在"<<endl;
		return ;
	}
	else
	{
		//删除节点如果为叶子节点
		if(NULL==p->LChild&&NULL==p->RChild)
		{
			if(!(p->Parent))//如果删除的是根节点
				root=NULL;
			else
			{
				//删除 节点是左孩子
				if(p->Parent->LChild==p)
					p->Parent->LChild=NULL;
				else
					p->Parent->RChild=NULL;
				free(p);
			}
		}
		//被删除节点只有一个左孩子
		else if(!(p->RChild)){
			//为根节点
			if(NULL==p->Parent){
				root=p->LChild;
				root->Parent=NULL;
			}
			else{
				if(p->Parent->LChild==p){
					p->Parent->LChild=p->LChild;
					p->LChild->Parent=p->Parent;
				}
				else{
					p->Parent->RChild=p->LChild;
					p->LChild->Parent=p->Parent;
				}
			}
			free(p);
		}
		//只有一个右节点
		else if(!p->LChild){
		
			if(NULL==p->Parent){
				root=p->RChild;
				root->Parent=NULL;
			}
			else{
				if(p->Parent->LChild==p){
					p->Parent->LChild=p->RChild;
					p->RChild->Parent=p->Parent;
				}
				else{
					p->Parent->RChild=p->RChild;
					p->RChild->Parent=p->Parent;
				}
			}
			free(p);  //释放节点
		}
		else
		{
			//找前驱
			k=p->LChild;
			while(k->RChild)
				k=k->RChild;

			//用前驱释覆盖被删除节点,并释放前驱的内存
			p->data=k->data;
			if(k->Parent->LChild==k){
				k->Parent->LChild=k->LChild;
				k->LChild->Parent=k->Parent;
			}
			else{
				k->Parent->RChild=k->LChild;
				k->LChild->Parent=k->Parent;
			}
			free(k);
		}
	}
}


释放树:递归释放,碰到虚节点,也就是NULL节点跳出递归

//释放树
void FreeTree(STree &T)
{
	if(T==NULL)
		return ;
	FreeTree(T->LChild);
	FreeTree(T->RChild);
	free(T);
}


完整代码

//二叉查找树创建、插入、删除
#include<iostream>
#include<stdio.h>

using namespace std;

typedef struct LNode
{
	int data; //值
	LNode *LChild;	//左孩子
	LNode *RChild;//右孩子
	LNode *Parent;//父节点
} *STree;

//插入操作
void insert(STree &root,int key){
	LNode *p=(STree)malloc(sizeof(LNode));
	p->data=key;
	p->LChild=p->RChild=p->Parent=NULL;
	if(NULL==root){		//如果树为空,则直接赋给根节点

		root=p;
		return;
	}
	if(NULL==root->LChild&&key<root->data){
	
		root->LChild=p;
		p->Parent=root;
		return;
	}
	if(NULL==root->RChild&&key>=root->data){
	
		root->RChild=p;
		p->Parent=root;
		return ;
	}
	if(root->data>key) 
		insert(root->LChild,key);
	else
		insert(root->RChild,key);
}
//查找,成功返回1,失败0,用节点引用记录查找成功的节点
int Search(const STree T,STree &p,int n)
{
	if(T&&T->data==n) //如果查找成功
	{
		p=T;
		return 1;
	}
	if(T->LChild&&(T->data>n))  Search(T->LChild,p,n);
	else if(T->RChild&&(T->data<n)) Search(T->RChild,p,n);
	else 
	{
		p=NULL;
		return 0;
	}
}

//中序遍历
void Mid(const STree T)
{
	if(T==NULL)
		return ;
	Mid(T->LChild);
	cout<<T->data<<" ";
	Mid(T->RChild);
}
//删除节点
void DeleteBST(STree &root,int n)
{
	//欲删除节点,要找到该节点的位置,及是否有左右孩子
	STree p;								//用来记录查找到要删除的节点的位置和其父节点的位置
	STree k=NULL; //缓冲节点,初始化为NULL是为了安全
	int flag=Search(root,p,n);  //查找删除节点是否存在,如果存在,则返回被删除节点p
	if(flag==0) {
		cout<<"要删除的节点不存在"<<endl;
		return ;
	}
	else
	{
		//删除节点如果为叶子节点
		if(NULL==p->LChild&&NULL==p->RChild)
		{
			if(!(p->Parent))//如果删除的是根节点
				root=NULL;
			else
			{
				//删除 节点是左孩子
				if(p->Parent->LChild==p)
					p->Parent->LChild=NULL;
				else
					p->Parent->RChild=NULL;
				free(p);
			}
		}
		//被删除节点只有一个左孩子
		else if(!(p->RChild)){
			//为根节点
			if(NULL==p->Parent){
				root=p->LChild;
				root->Parent=NULL;
			}
			else{
				if(p->Parent->LChild==p){
					p->Parent->LChild=p->LChild;
					p->LChild->Parent=p->Parent;
				}
				else{
					p->Parent->RChild=p->LChild;
					p->LChild->Parent=p->Parent;
				}
			}
			free(p);
		}
		//只有一个右节点
		else if(!p->LChild){
		
			if(NULL==p->Parent){
				root=p->RChild;
				root->Parent=NULL;
			}
			else{
				if(p->Parent->LChild==p){
					p->Parent->LChild=p->RChild;
					p->RChild->Parent=p->Parent;
				}
				else{
					p->Parent->RChild=p->RChild;
					p->RChild->Parent=p->Parent;
				}
			}
			free(p);  //释放节点
		}
		else
		{
			//找前驱
			k=p->LChild;
			while(k->RChild)
				k=k->RChild;

			//用前驱释覆盖被删除节点,并释放前驱的内存
			p->data=k->data;
			if(k->Parent->LChild==k){
				k->Parent->LChild=k->LChild;
				k->LChild->Parent=k->Parent;
			}
			else{
				k->Parent->RChild=k->LChild;
				k->LChild->Parent=k->Parent;
			}
			free(k);
		}
	}
}

//释放树
void FreeTree(STree &T)
{
	if(T==NULL)
		return ;
	FreeTree(T->LChild);
	FreeTree(T->RChild);
	free(T);
}
int main()
{
	int temp;
	int n,m;
	STree root=NULL;
	STree p=NULL;
	//T->Parent=NULL;
	cout<<"输入数的个数"<<endl;
	cin>>n;
	for(int i=0;i<n;i++)
	{
		cin>>temp;
		insert(root,temp);
	}
	Mid(root);
	cout<<"输入删除的元素"<<endl;
	cin>>m;
	DeleteBST(root,m);
	Mid(root);
	FreeTree(root);
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值