二叉查找树
原理
- 二叉查找树,又叫作二叉搜索树、二叉排序树,是一种对查找和排序都有用的特殊二叉树
- 二叉查找树或是空树,或是满足如下性质的二叉树:
①若其左子树非空,则左子树上所有节点的值均小于根节点的值;
②若其右子树非空,则右子树上所有忽而短板的值均大于根节点的值;
③其左右子树本身各是一棵二叉查找树。 - 二叉查找树的特性:左子树<根<右子树,即二叉查找树的中序遍历是一个递增序列。
二叉查找树的查找
- 因为二叉查找树的中序遍历有序性,所以查找与二分查找类似,每次都缩小查找范围,查找效率较高
算法设计
- 若二叉查找树为空,查找失败,则返回空指针
- 若二叉查找树非空,则将待查找关键字
x
与根节点的关键字T->data
进行比较。
- 若
x == T->data
,查找成功,则返回T
- 若
x < T->data
,则递归查找左子树 - 若
x < T->data
,则递归查找右子树
二叉树的插入
- 因为二叉查找树的中序遍历存在有序性,所以首先要查找待插入关键字的插入位置,当查找不成功时,再将待插入关键字作为新的叶子节点称为最优一个查找节点的左孩子或右孩子
算法设计
- 若二叉查找树为空,则创建一个新的节点
s
,将待插入关键字放入新节点的数据域,将s
节点作为根结点,左右子树均为空。 - 若二叉查找树非空,则将待查找关键字
x
与根结点的关键字T->data
进行比较。
- 若
x<T->data
,则将x
插入左子树中 - 若
x>T->data
,则将x
插入右子树中
二叉查找树的创建
- 二叉查找树的创建可以从空树开始,按照输入关键字的顺序依次进行插入操作,最终得到一颗二叉查找树。
算法设计
- 初始化二叉查找树为空树,
T = NULL
; - 输入一个关键字
x
,将x
插入二叉查找树T
中; - 重复步骤2,直到关键字输入完毕
二叉查找树的删除
- 首先要在二叉查找树中找到待删除节点,然后执行删除操作。假设指针
p
指向待删除节点,指针f
指向p
的双亲节点。根据待删除节点所在位置的不同,删除操作的处理方法也不同,可以分为下面三种情况。
- 被删除节点的左子树为空,如果被删除节点的左子树为空,则令其右子树子承父业代替其位置即可。
- 被删除节点的右子树为空。如果被删除节点的右子树为空,则令其左子树子承父业代替其位置即可。
- 被删除节点的左右子树均不为空。根据二叉查找树的中序有序性,删除该节点时,可以用其直接前驱(或直接后继)代替其位置,然后删除其直接前驱(或直接后继)即可。
算法设计
- 在二叉查找树中查找待删除关键字的位置,
p
指向待删除节点,f
指向p
的双亲节点,如果查找失败,则返回。 - 如果查找成功,则分三种情况进行删除操作。
- 如果被删除节点的左子树为空,则令其右子树子承父业代替其位置即可。
- 如果被删除节点的右子树为空,则令其左子树子承父业代替其位置即可。
- 如果被删除节点的左右子树均不为空,则令其直接前驱(或者直接后继)代替它,再删除其直接前驱(或直接后继)
算法实现
#include<iostream>
using namespace std;
#define ENDFLAG -1
typedef int ElemType;
typedef struct BSTNode{
ElemType data; //结点数据域
BSTNode *lchild,*rchild; //左右孩子指针
}BSTNode,*BSTree;
BSTree SearchBST(BSTree T,ElemType key); //二叉排序树的递归查找
void InsertBST(BSTree &T,ElemType e); //二叉排序树的插入
void CreateBST(BSTree &T ); //二叉排序树的创建
void DeleteBST(BSTree &T,char key);
void InOrderTraverse(BSTree &T);//中序遍历
int main()
{
BSTree T;
cout<<"请输入一些整型数,-1结束"<<endl;
CreateBST(T);
cout<<"当前有序二叉树中序遍历结果为"<<endl;
InOrderTraverse(T);
cout<<endl;
ElemType key;//待查找或待删除内容
cout<<"请输入待查找关键字"<<endl;
cin>>key;
BSTree result=SearchBST(T,key);
if(result)
cout<<"找到"<<key<<endl;
else
cout<<"未找到"<<key<<endl;
cout<<"请输入待删除关键字"<<endl;
cin>>key;
DeleteBST(T,key);
cout<<"当前有序二叉树中序遍历结果为"<<endl;
InOrderTraverse(T);
return 0;
}
BSTree SearchBST(BSTree T,ElemType key){
//若查找成功,则返回指向该数据元素结点的指针,否则返回空指针
if((!T)|| key==T->data)
return T;
else if (key<T->data)
return SearchBST(T->lchild,key);//在左子树中继续查找
else
return SearchBST(T->rchild,key); //在右子树中继续查找
}
void InsertBST(BSTree &T,ElemType e){
//当二叉排序树T中不存在关键字等于e的数据元素时,则插入该元素
if(!T)
{
BSTree S=new BSTNode; //生成新结点
S->data=e; //新结点S的数据域置为e
S->lchild=S->rchild=NULL;//新结点S作为叶子结点
T=S; //把新结点S链接到已找到的插入位置
}
else if(e<T->data)
InsertBST(T->lchild,e );//插入左子树
else if(e>T->data)
InsertBST(T->rchild,e);//插入右子树
}
void CreateBST(BSTree &T ){
//依次读入一个关键字为key的结点,将此结点插入二叉排序树T中
T=NULL;
ElemType e;
cin>>e;
while(e!=ENDFLAG)//ENDFLAG为自定义常量,作为输入结束标志
{
InsertBST(T,e); //插入二叉排序树T中
cin>>e;
}
}
void DeleteBST(BSTree &T,char key){
//从二叉排序树T中删除关键字等于key的结点
BSTree p=T;BSTree f=NULL;
BSTree q;
BSTree s;
if(!T) return; //树为空则返回
while(p)//查找
{
if(p->data==key) break; //找到关键字等于key的结点p,结束循环
f=p; //f为p的双亲
if (p->data>key)
p=p->lchild; //在p的左子树中继续查找
else
p=p->rchild; //在p的右子树中继续查找
}
if(!p) return; //找不到被删结点则返回
//三种情况:p左右子树均不空、无右子树、无左子树
if((p->lchild)&&(p->rchild))//被删结点p左右子树均不空
{
q=p;
s=p->lchild;
while(s->rchild)//在p的左子树中继续查找其前驱结点,即最右下结点
{
q=s;
s=s->rchild;
}
p->data=s->data; //s的值赋值给被删结点p,然后删除s结点
if(q!=p)
q->rchild=s->lchild; //重接q的右子树
else
q->lchild=s->lchild; //重接q的左子树
delete s;
}
else
{
if(!p->rchild)//被删结点p无右子树,只需重接其左子树
{
q=p;
p=p->lchild;
}
else if(!p->lchild)//被删结点p无左子树,只需重接其右子树
{
q=p;
p=p->rchild;
}
/*――――――――――将p所指的子树挂接到其双亲结点f相应的位置――――――――*/
if(!f)
T=p; //被删结点为根结点
else if(q==f->lchild)
f->lchild=p; //挂接到f的左子树位置
else
f->rchild=p;//挂接到f的右子树位置
delete q;
}
}
void InOrderTraverse(BSTree &T){
if(T)
{
InOrderTraverse(T->lchild);
cout<<T->data<<"\t";
InOrderTraverse(T->rchild);
}
}
输入与输出:
请输入一些整型数,-1结束
35 98 65 44 34 87 98 -1
当前有序二叉树中序遍历结果为
34 35 44 65 87 98
请输入待查找关键字
44
找到44
请输入待删除关键字
87
当前有序二叉树中序遍历结果为
34 35 44 65 98
训练1:落叶
题目描述
给定一个字母二叉搜索树的树叶删除序列,输出树的先序遍历。
输入:输入包含多个测试用例。每个测试用例都是一行或多行大写字母序列,每行都给出按上述描述步骤从二叉搜索树中删除的树叶,每行给出的字母都按字母升序排列。在测试用例之间以一行分隔,该行仅包含一个星号“*”。在最后一个测试用例后给出一行,该行仅给出一个符号“$”。在输入中没有空格或空行。
输出:对于每个测试用例,都有唯一的二叉搜索树,单行输出该树的先序遍历。