二叉搜索树Binary Search Tree(BSTs)又名二叉排序树,二叉查找树。而能够自平衡的叫平衡搜索树,包括AVL trees, 2-3 trees, 2-3-4 trees, B-trees, Red-Black Trees红黑树,skip lists跳跃表。
在二叉搜索树的基础上,又有最优二叉搜索树。
在此之前先说说三种遍历方式。
中序遍历首先遍历左子树,然后访问根结点,最后遍历右子树。在遍历左、右子树时,仍然先遍历左子树,再访问根结点,最后遍历右子树。即:
若二叉树为空则结束返回
否则:
(1)中序遍历左子树。
(2)访问根结点。
(3)中序遍历右子树。
中序遍历
注意的是:遍历左右子树时仍然采用中序遍历方法。
如右图所示二叉树
中序遍历结果:DBEAFC
中序遍历的时间复杂度为:O(n)。
如果一棵二叉排序树的节点值是数值,中序遍历的结果为升序排列的数组。可以利用该性质检测一棵树是否为二叉排序数。
已知前序遍历和后序遍历,不能确定唯一的中序遍历。
void BinTree::preOrder(Node *r)//递归实现先序遍历
{
if(r==NULL)
{
return ;
}
else
{
cout<<r->data<<" ";
preOrder(r->left);
preOrder(r->right);
}
}
void BinTree::InOrder(Node *r)//递归实现中序遍历 { if(r==NULL) { return ; } else { InOrder(r->left); cout<<r->data<<" "; InOrder(r->right); } } void BinTree::PostOrder(Node *r)//递归实现后序遍历 { if(r==NULL) { return ; } else { PostOrder(r->left); PostOrder(r->right); cout<<r->data<<" "; } }
一、二叉搜索树的定义
二叉搜索树或者是一棵空树,或者是具有下列性质的二叉树:
每个结点都有一个作为搜索依据的关键码(key),所有结点的关键码互不相同。
二、查询操作
在二叉搜索树中,查询操作时很核心的一个操作,在插入节点的时候,需要查看改节点是否已经存在,如果存在那么插入操作失败。并且在删除节点而不调整二叉树时,使用的策略和步骤是和查询操作一样的。
查询步骤如下:
/********************************************************************
Method: SearchBST
Description:
Access: public
Returns: int
Parameter: T: the tree that will be searched, f:the father tree of the
tree that will be searched p:point to the elements
that =key, or when result =0; point to the last leaf node
********************************************************************/
void SearchBST(BiTree T,int key,BiTree f,BiTree &p,int& result)
{
result = 0;
if(T == NULL)
{
p=f;
result = 0;
}
else if(key>T->data)
{
SearchBST(T->rchild,key,T,p,result);
}
else if(key<T->data)
{
SearchBST(T->lchild,key,T,p,result);
}
else if(key == T->data)
{
p=T;
result = 1;
}
}
使用返回值的版本如下:
int SearchBST(BiTree T,int key,BiTree f,BiTree &p)
{
int tmp1,tmp2;
tmp1=tmp2=0;
if(!T) {p=f;return 0;} //查找不成功
else if(key==T->data) {p=T;return 1;} //查找成功
else if(key<T->data) tmp1=SearchBST(T->lchild,key,T,p); //在左子树中继续查找
else tmp2=SearchBST(T->rchild,key,T,p); //在右子树中继续查找
if(tmp1||tmp2) return 1; //若在子树中查找成功,向上级返回1
else return 0; //否则返回0*/
}
三、插入操作
每次结点的插入,都要先进行搜索操作,(搜索不成功;报告该空节点的父亲节点,最后停留在的叶子节点)。然后把新结点作为改叶结点的子节点插入。
int InsertBST(BiTree &T,int key)
{
BiTree p,s;
int result = 0;
SearchBST(T,key,NULL,p,result);
if(result == 0) //查找不成功,插入
{
s = new BiTNode;
s->data=key;
s->lchild=s->rchild=NULL;
if(p == NULL) T=s; //被插结点*s为新的根结点
else if(key<p->data) p->lchild=s; //被插结点*s为左孩子
else p->rchild=s; //被插结点*s为右孩子
return 1; //成功插入
}
else return 0; //树中已存在关键字为e的数据元素
}
四、删除操作
在B中,16的左子树空,16用他的右子树填补
在C中,5的左右子树都不为空,采取找到右子树最小值(中序查找到的第一个值),将6填入5,然后6变成了一个hole,递归执行直到最后一个取代的值的左右子树有一个为空,结束。原则是这样子,但是一般都不会使用递归实现。
取代的是,p是5,q从5开始,s是5的右子树,即q一直是s的前驱。然后s向左走到尽头,q一直保存前驱,最后s变为6,q为10, 然后将p上的值存储为6,将6的右子树接入到10的左子树
第一步,做类似查找的操作:
void DeleteBST(BiTree &T,int key, int& result)
{
result = 0;
if(T==NULL)
{
result = 0; //要搜索的子树为空
}
else
{
if(key==T->data)//找到关键字等于key的数据元素并删除它
{
Delete(T); //在二叉排序树中删除结点p,并重接它的左或右子树
result = 1;
}
else if(key<T->data) //继续在左子树中删除
{
DeleteBST(T->lchild,key,result);
}
else //继续在右子树中删除
{
DeleteBST(T->rchild,key,result);
}
}
}
第二步、实现Delete(T),删除节点p,重接它的 左右子树。
方法一:找到右子树最小的值。
方法二、找到左子树最大的值。
void Delete(BiTree &p)
{//在二叉排序树中删除结点p,并重接它的左或右子树
BiTree s,q;
if(p->rchild == NULL) //右子树空,只需重接它的左子树
{
cout<<"p value"<<p->data<<endl;
q=p;
p=p->lchild;
free(q);
}
else if(p->lchild == NULL) //左子树空,只需重接它的右子树
{
cout<<"p2 value"<<p->data<<endl;
q=p;
p=p->rchild;
free(q);
}
else //左右子树均不空
{
q=p;//q一直是s的前驱,负责保存s游走后的位置
s=p->rchild;//s不断向左游走,转右,向左走到尽头
while(s->lchild)
{
q=s;s=s->lchild;
}
p->data=s->data; //q的值也被改变
cout<<"s value"<<s->data<<endl;
cout<<"q value"<<q->data<<endl;
cout<<"p value"<<p->data<<endl;
if(q!=p) q->lchild=s->rchild;
else //删除78, 左右为65,94,q没有前进过地址没变,但是值变为了94
{
q->rchild=s->lchild;
}
free(s);
}
}
整个可执行程序的代码如下:
演示的二叉堆为:
</pre><p></p><div style="top: 576px;"><pre name="code" class="cpp">#include <iostream>
using namespace std;
#define Maxsize 100
typedef struct BiTNode //定义二叉树节点结构
{
int data; //结点的数据域
struct BiTNode *lchild,*rchild; //左右孩子指针域
}BiTNode,*BiTree;
BiTNode *CreatBST(int A[],int n);
void SearchBST(BiTree,int,BiTree,BiTree&,int& result); //在二叉排序树中查找元素
int InsertBST(BiTree &,int); //在二叉排序树中插入元素
int DeleteBST(BiTree &,int); //在二叉排序树中删除元素
void Delete(BiTree &); //删除二叉排序树的根结点
void InorderBST(BiTree); //中序遍历二叉排序树,并显示
void inorder(BiTree T);
int A[Maxsize];
BiTNode *CreatBST(int A[],int n) //由数组A中的关键字建立一棵二叉排序树
{
BiTNode *bt=NULL; //初始bt 为空树
int i=0;
while(i<n)
if(InsertBST(bt,A[i])==1) //将数组A[i]插入二叉排序树bt中
{
printf(" Step%d,Insert:%d:",i+1,A[i]);
InorderBST(bt);
printf("\n");
i++;
}
return bt; //返回建立的二叉排序树的根指针
}
void InorderBST(BiTree T)
{//以中序方式遍历二叉排序树T,并显示
if(T!=NULL)
{
printf("%d",T->data);
if(T->lchild!=NULL||T->rchild!=NULL)
{
printf("(");
InorderBST(T->lchild);//递归调用中序遍历函数
if(T->rchild!=NULL)
printf(",");
InorderBST(T->rchild); //递归调用中序遍历函数
printf(")");
}
}
}
void inorder(BiTree T)
{
if(T!=NULL)
{
inorder(T->lchild);
cout<<" "<<T->data;
inorder(T->rchild);
}
}
/********************************************************************
Method: SearchBST
Description:
Access: public
Returns: int
Parameter: T: the tree that will be searched, f:the father tree of the
tree that will be searched p:point to the elements
that =key, or when result =0; point to the last leaf node
********************************************************************/
void SearchBST(BiTree T,int key,BiTree f,BiTree &p,int& result)
{
result = 0;
if(T == NULL)
{
p=f;
result = 0;
}
else if(key>T->data)
{
SearchBST(T->rchild,key,T,p,result);
}
else if(key<T->data)
{
SearchBST(T->lchild,key,T,p,result);
}
else if(key == T->data)
{
p=T;
result = 1;
}
}
int InsertBST(BiTree &T,int key)
{
BiTree p,s;
int result = 0;
SearchBST(T,key,NULL,p,result);
if(result == 0) //查找不成功,插入
{
s = new BiTNode;
s->data=key;
s->lchild=s->rchild=NULL;
if(p == NULL) T=s; //被插结点*s为新的根结点
else if(key<p->data) p->lchild=s; //被插结点*s为左孩子
else p->rchild=s; //被插结点*s为右孩子
return 1; //成功插入
}
else return 0; //树中已存在关键字为e的数据元素
}
int DeleteBST(BiTree &T,int key)
{//若二叉排序树T中存在关键字等于key的数据元素时,则删除该数据元素结点
//并返回1,否则返回0
int tmp1,tmp2;
tmp1=tmp2=0;
if(!T) return 0; //不存在关键字等于key的数据元素
else
{
if(key==T->data) {Delete(T); return 1;} //找到关键字等于key的数据元素并删除它
else if(key<T->data) tmp1=DeleteBST(T->lchild,key); //继续在左子树中删除
else tmp2=DeleteBST(T->rchild,key); //继续在右子树中删除
if(tmp1||tmp2) return 1; //在子树中删除成功,返回1
else return 0; //不存在该元素,返回0
}
}
void Delete(BiTree &p)
{//在二叉排序树中删除结点p,并重接它的左或右子树
BiTree s,q;
if(p->rchild == NULL) //右子树空,只需重接它的左子树
{
cout<<"p value"<<p->data<<endl;
q=p;
p=p->lchild;
free(q);
}
else if(p->lchild == NULL) //左子树空,只需重接它的右子树
{
cout<<"p2 value"<<p->data<<endl;
q=p;
p=p->rchild;
free(q);
}
else //左右子树均不空
{
q=p;//q一直是s的前驱,负责保存s游走后的位置
s=p->rchild;//s不断向左游走,转右,向左走到尽头
while(s->lchild)
{
q=s;s=s->lchild;
}
p->data=s->data; //q的值也被改变
cout<<"s value"<<s->data<<endl;
cout<<"q value"<<q->data<<endl;
cout<<"p value"<<p->data<<endl;
if(q!=p) q->lchild=s->rchild;
else //删除78, 左右为65,94,q没有前进过地址没变,但是值变为了94
{
q->rchild=s->lchild;
}
free(s);
}
}
void main()
{
BiTree T,p;
int ch,keyword;
char j='y';//控制程序结束与否
int temp;
printf("Creat the BST!\n");
const int n = 10;
int A[n]={53,17,78,9,45,65,94,23,81,88};
T=CreatBST(A,n);//调用建树函数建树
inorder(T);
while(j!='n')
{
printf("1.display\n");
printf("2.search\n");
printf("3.insert\n");
printf("4.delete\n");
printf("5.exit\n");
scanf(" %d",&ch); //输入操作选项
switch(ch)
{ case 1:
if(!T) printf("The BST has no elem.\n");
else {InorderBST(T);printf("\n");}//中序遍历并显示
break;
case 2:
printf("Input the keyword of elem to be searched(a number):");
scanf(" %d",&keyword); //输入要查找元素的关键字
SearchBST(T,keyword,NULL,p,temp);//查找
if(!temp) printf("%d isn't existed!\n",keyword); //没有找到
else printf("%d has been found!\n",keyword); //成功找到
break;
case 3:
printf("Input the keyword of elem to be inserted(a number):");
scanf(" %d",&keyword); //输入要插入元素的关键字
temp=InsertBST(T,keyword);//插入
if(!temp) printf("%d has been existed!\n",keyword); //该元素已经存在
else printf("Sucess to inert %d!\n",keyword); //成功插入
break;
case 4:
printf("Input the keyword of elem to be deleted(a number):");
scanf(" %d",&keyword); //输入要删除元素的关键字
temp=DeleteBST(T,keyword);//删除
InorderBST(T);
if(!temp) printf("%d isn't existed!\n",keyword); //该元素不存在
else printf("Sucess to delete %d\n",keyword); //成功删除
break;
case 5: j='n';//跳出循环,结束程序
}
}
printf("The program is over!\nPress any key to shut off the window!\n");
getchar();getchar();
}