概述
搜索二叉树满足一下条件:
- 是一棵二叉树
- 这可树上的任意一个节点满足:若他的右子树不为空,则右子树上的所有节点的值大于该节点的值
- 这可树上的任意一个节点满足:若他的左子树不为空,则左子树上的所有节点的值小于该节点的值
- 它的的左子树和右子树也是二叉搜索树
如图,就是一个标准的二叉搜索树
下图就是有一个错误的二叉搜索树
二叉树节点构建
class BstNode
{
private:
BstNode*left,*right;
int data;
public:
BstNode(int Data,BstNode*Left=NULL,BstNode*Right=NULL):data(Data),left(Left),right(Right){};
void set_data(int item)
{
data=item;
}
int get_data()const
{
return data;
}
void set_left(BstNode*l)
{
left=l;
}
BstNode*get_left()const
{
return left;
}
void set_right(BstNode*r)
{
right=r;
}
BstNode*get_right()const
{
return right;
}
};
树的构建
class Bst
{
private:
BstNode*root;
public:
Bst(BstNode*t=NULL):root(t){};
~Bst()
{
destory(root);
}
void set_root(BstNode*iroot)
{
root=iroot;
}
BstNode*get_root() const
{
return root;
}
//销毁
void destory(BstNode*root);
//插入元素
BstNode*insert(BstNode*root,int val);
//查找任意元素(递归)
BstNode*Find(BstNode*root,int val);
查找任意元素(非递归)
BstNode*iterFind(BstNode*root,int val);
//查找最大元素
BstNode*FindMax(BstNode*root);
//查找最小元素
BstNode*FindMin(BstNode*root);
//中序
void in_order(BstNode*root)const;
//删除元素
BstNode*Delete(BstNode*root,int val);
};
查找操作
二叉搜索树最大的优点在于他的查找速率很高
所要查找的值:val
所在节点的值:data
- 1.当data>val时,所要查找的值在该树的左子树上,进入左子树继续查找。
- 2.当data<val时,所要查找的值在该树的右子树上,进入右字数进行查找。
- 3.当data==val时,该节点就是所要查找的节点。
eg: 在下面树的上查找 16(val==16)
过程如下:
1.当data<val时,所要查找的值在该树的右子树上,进入右字数进行查找。
2.当data>val时,所要查找的值在该树的左子树上,进入左子树继续查找。
3.3.当data==val时,该节点就是所要查找的节点。
代码实现
递归版
//查找任意元素(递归)
BstNode*Bst::Find(BstNode*root,int val)
{
if(root==NULL)
return NULL; //查找失败
if(val<root->get_data()) //在左子树上
return Find(root->get_left(),val);
else if(val>root->get_data()) //在有子树上
return Find(root->get_right(),val);
else
return root; //找到了
}
因为当这棵树特别庞大时,递归可能会导致栈溢出的问题并且递归相对于循环效率要低,所以可以改成循环的方式
//查找任意元素(非递归)
BstNode*Bst::iterFind(BstNode*root,int val)
{
while(root)
{
if(val<root->get_data())
root=root->get_left();
if(val>root->get_data())
root=root->get_right();
}
return NULL;
}
二叉搜索树的中序
二叉搜索树有一个特点,他的中序是一个递增的序列如下图所示
中序:
7 8 9 15 16 20 21 25
因此判断一个二叉树是否为二叉搜索树也可以看他的中序是否为一个递增的序列
void Bst::in_order(BstNode*root)const
{
if(root==NULL)
return ;
in_order(root->get_left());
cout<<root->get_data()<<" ";
in_order(root->get_right());
}
查找最大元素,最小元素
根据二叉搜索树的特性,最小值会在最左边,最大值会在最右边
查找最大元素
BstNode*Bst::FindMax(BstNode*root)
{
if(root==NULL)
return NULL;
while(root->get_right())
{
root=root->get_right();
}
return root;
}
查找最小元素
BstNode*FindMin(BstNode*root)
{
if(root==NULL)
return NULL;
while(root->get_left())
{
root=root->get_left();
}
return root;
}
插入操作
插入操作与查找操作很类似,但是插入时要一直走到后面,遇到NULL为止,然后创建一个新节点,取代该空指针
BstNode*Bst::insert(BstNode*root,int val)
{
if(root==NULL)//如果根节点为空,就返回该节点
{
root=new BstNode(val);
root->set_left(nullptr);
root->set_right(nullptr);
}
else//根节点不为空
{
if(val<root->get_data()) //插入右子树
{
root->set_left(insert(root->get_left(),val));
}
else if(val>root->get_data()) //插入左子树
{
root->set_right(insert(root->get_right(),val));
}
//如果该节点已存在,什么都不用做
}
return root;
}
删除操作
该操作可以说是最难得了
要删除的节点有三种情况(默认要删除的节点都存在)
- 1.该节点是叶子节点,直接删除就可以了
- 2.该节点有一个左子树或有一个右子树
二叉搜索树,任意一个节点的(默认左右子树都存在),左子树上任意一个节点的值都是小于该节点上的值的,相反右子树上任意一个节点的值都是大于该节点上的值的。
所以要删除该类型的节点只需要让该节点的父节点指向该节点的子节点
删除完成
- 要删除的节点含有左右节点
当删除的结点有左、右两棵子树,我们删除该结点后需要考虑怎么处置它的孩子结点。此时最简单的办法就是用另一结点替代被删除结点,那我们要用哪一个结点呢?根据二叉搜索树的定义:每一个结点的右孩子都比自己大,左孩子都比自己小。要取哪一个结点替代被删除的结点同时又保证该特性呢?所以根据此情况,我们很快就能判断出用被删除结点的右子树的最小元素或者左子树的最大元素替代被删除结点。
代码如下:
//删除较为麻烦会有三种情况
//1.目标节点没有子结点
//2.目标节点只有一个子节点
//3.目标节点有两个子结点
BstNode*Bst::Delete(BstNode*root,int val)
{
if(root==NULL)
cout<<"要删除的元素未找到"<<endl;
else
{
if(val<root->get_data())
{
root->set_left(Delete(root->get_left(),val));
}
else if(val>root->get_data())
{
root->set_right(Delete(root->get_right(),val));
}
else
{
if(root->get_right()&&root->get_left()) //有左右节点
{
BstNode*temp=FindMax(root->get_left());
root->set_data(temp->get_data());
root->set_left(Delete(root->get_left(),temp->get_data()));
}
else
{
BstNode*temp=root;
if(root->get_left()==NULL) //只有右节点或没有节点
root=root->get_right();
else
root=root->get_left(); //只有左节点
delete temp;
}
}
}
return root;
}