二叉搜索树(基于C/C++)

简介

搜索树是一种可以进行插入,搜索,删除等操作的数据结构,可以用作字典或优先级队列。二叉搜索树是最简单的搜索树。其左子树的键值<=根节点的键值,右子树的键值>=根节点的键值。

如果共有n个元素,那么每次操作需要的O(log n)的时间.

常用知识点

  1. 满二叉树 : 一棵深度为k,且有2^k-1个节点的二叉树,称为满二叉树。这种树的特点是每一层上的节点数都是最大节点数。
  2. 完全二叉树 : 而在一棵二叉树中,除最后一层外,若其余层都是满的,并且最后一层要么是满的,要么在右边缺少连续若干节点,则此二叉树为完全二叉树。具有n个节点的完全二叉树的深度为floor(log2n)+1。深度为k的完全二叉树,至少有2^(k-1)个叶子节点,至多有2^k-1个节点。

基本操作

  1. 查找(search)
  2. 插入(insert)
  3. 删除(remove)

操作原理

查找

假设查找的值为x,从根节点的值开始比对,如果小于根节点的值,则往左儿子继续查找,如果大于根节点的值,则往右儿子继续查找.依次类推.直到当前节点的值等于要查找的值.

以查找数值10为例

插入

按照查找的步骤即可找到插入值应该在的位置.

以插入数值6为例

删除

删除操作实现起来最为麻烦,因为删除某个节点后, 如果它有子孙,还有将它的子孙接到原树上. 而它的子孙可能出现的情况较多, 可以分为一下三类.

1. 需要删除的节点没有左儿子, 则把右儿子接到二叉树上. 如下图,若删除值为5的节点,只需要将值为7的节点接到原先5的节点即可

2. 需要删除的节点的左儿子没有右儿子, 那么把左儿子接到二叉树上. 如下图, 若删除值为5的节点, 只需将值为3的节点接到原先5的位置即可.

3. 以上两种情况都不满足, 就把左儿子的子孙中最大的节点, 即右子树的右子树的...右子树, 提到需要删除的节点位置. 如下图, 若删除值位5的节点, 先找到其子孙中值最大的节点, 即值为9的节点, 然后将该节点提到5的位置.

代码实现

//BST节点 
struct node{
//	值 
	int val;
//	指向左右子树的指针 
	node *lch,*rch;
};

//	插入数值x 
node *insert(node *p,int x){ 
	if(p==NULL){
//		如果p为空指针,则申请一个节点的空间并将左右子树设为空,返回该节点 
		node *q = new node;
		q->val = x;
		q->lch = q->rch = NULL;
		return q;
	}else{
//		如果p不为空,将x与p的值进行比较, 如果x小于val,则将x插入左子树,否则插入右子树 
		 if(x<p->val)	p->lch=insert(p->lch,x);
		 else p->rch = insert(p->rch,x);
		 return p;
	}
}

//	查找数值x,p为根节点 
bool find(node *p,int x){
	if(p==NULL)	return false;
	else if(x==p->val)	return true;
	else if(x<p->lch)	return find(p->lch,x);
	else return find(p->rch,x); 
} 

//	删除数值x
node *remove(node *p,int x){
	if(p==NULL)	return NULL;
//	找到要删除的节点 
	else if(x<p->val)	p->lch=remove(p->lch,x);
	else if(x>p->val)	p->rch=remove(p->rch,x);
//	如果要删除的节点没有左儿子,那么就把右儿子提上去 
	else if(p->lch==NULL){
		node *q=p->rch;
		delete p;
		return q;
//	如果要删除的节点的左儿子没有右儿子,就把左儿子提上去 
	}else if(p->lch->rch==NULL){
		node *q = p->lch;
		q->rch = p->rch;
		delete p;
		return q;
//	如果以上情况都不满足,就把左儿子的子孙中最大的节点(右儿子的右儿子的。。。右儿子)提到需要删除的节点上 
	}else{
		node *q;
//		用for循环进行遍历,这一招妙啊 
		for(q=p->lch;q->rch->rch!=NULL;q=q->rch);
		node *r=q->rch;
		q->rch = r->lch;
		r->lch=p->lch;
		r->rch=p->rch;
		delete p;
		return r;
	}
	return p;
}

代码测试

#include<iostream>
#include "BST.h"
using namespace std;

int main(){
//	声明一个指向根节点的指针 
	node *root=NULL;
//	判断二叉树是否为空 
	if(root==NULL)	cout<<"empty"<<endl;
//	插入数值 
	root = insert(root,1);
//	查找数值
	if(find(root,1))	cout<<1<<endl;
//	删除数值
	root=remove(root,1); 
//	再次判空 
	if(root==NULL)	cout<<"empty"<<endl;
	
	return 0;
}

 运行结果

本文参考了<<挑战程序设计竞赛>>一书的P77-81, 部分图片截取自书上.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值