二叉排序树(二叉查找树)的定义:
二叉排序树或者是一棵空树,或者是一棵具有以下性质的二叉树:
(1)若它的左子树不为空,则左子树上所有结点的值均小于根结点的值;
(2)若它的又子树 不为空,则右子树上所有结点的值均大于根结点的值;
(3)它的左、右子树都是二叉排序树。
二叉排序树的定义是递归的。由此可得到二叉排序树的一个重要性质:中序遍历一棵二叉排序树可得到有序递增序列。
二叉排序树结点数据结构的定义(包括关键字项和其他数据项):
//每个结点数据域的数据类型
typedef struct
KeyType key; //关键字项
InfoType otherinfo; //其他数据项
}ElemType;
//二叉排序树结点的数据结构
typedef struct BSTNode{
ElemType data; //数据域
struct BSTNode *lchild,*rchild; //左右孩子指针域
}BSTNode,*BSTree;
下面的操作,我们使用简化的数据结构定义,我们这里将结点的数据域直接指定为int类型:
typedef struct BSTNode{
int data; //数据域
struct BSTNode *lchild,*rchild; //左右孩子指针域
}BSTNode,*BSTree;
二叉排序树的递归查找:
(1)若树为空,查找失败,返回空指针;
(2)若树非空,将给定的值key和结点元素值T->data比较:
a.若key 等于 T->data,查找成功,返回根结点的地址;
b.若key 小于 T->data,递归查找左子树;
c.若key 大于 T->data,递归查找右子树。
//二叉排序树的递归查找
BSTree SearchBST(BSTree &T, int key){
//在根指针T所指的二叉树中查找关键字等于key的数据元素
//若查找成功,则返回指向该数据元素结点的指针,否则返回空指针
if(!T || key==T->data){
return T;
} else if(key<T->data){
return SearchBST(T->lchild, key);
}else {
return SearchBST(T->rchild, key);
}
}
二叉排序树的插入:
(1)若树为空,将新结点S做为根结点插入到空树中;
(2)若树非空,将新结点的值key与T->data做比较:
a.若key小于T->data,则将新结点S插入到左子树;
b.若key大于T->data,则将新结点S插入到右子树。
//二叉排序树的递归插入算法
void InsertBST(BSTree &T, int e){
if(!T){
BSTNode *s=new BSTNode;
s->data=e;
s->lchild=NULL;
s->rchild=NULL;
T=s;
} else if(e<T->data){
InsertBST(T->lchild, e);
}else if(e>T->data){
InsertBST(T->rchild, e);
}
}
创建二叉排序树:
(1)将二叉排序树初始化为空树;
(2)读入一个关键字为key的新结点;
(2)如果输入的key不是输入结束标志,循环以下操作:
a.将此结点插入到二叉排序树中;
b.读入一个关键字为key的新结点。
//二叉排序树的创建
void CreateBST(BSTree &T){
T=NULL;
int e;
printf("请输入根点元素值(-1表示输入结束):");
scanf("%d", &e);
//输入-1表示结束
while(e!=-1){
InsertBST(T, e);
printf("请输入结点元素值(-1表示输入结束):");
scanf("%d", &e);
}
}
二叉排序树的删除:
(1)若*p结点为叶子结点, 即凡和P R 均为空树。 由千删去叶子结点不破坏整棵树的结构,
则只需修改其双亲结点的指针即可。
f->lchild = NULL;
(2)若*p结点只有左子树PL或者只有右子树PR , 此时只要令PL 或PR直接成为其双亲结点
*f的左子树即可。f->lchild = p ->lchild; (或f->lchild= p ->rchild;)
(3) 若*p结点的左子树和右子树均不空。在删去*p结点之前,中序遍历
该二叉树得到的序列为{ …CL,C … QL,Q,SL,S,P,PR,F … }'在删去*p之后,为保持其他元素之间的相对位
置不变,可以有两种处理方法:
a.令*p的左子树为*f的左子树, 而*p的右子树为*s的右子树。f->lchild = p ->lchild; s ->rchild = p ->rchild;
b.令*p 的直接前驱(或直接后继) 替代*p, 然后再从二叉排序树中删去它的直接前驱(或
直接后继)。 当以直接前驱*s替代*p时, 由千*s只有左子树S L , 则在删去*s
之后,只要令S L 为*s的双亲*q的右子树即可
//从二叉排序树中删除关键字等于key的结点
void DeleteBST(BSTree &T, int key){
BSTree p, f; //查找关键字等于key的结点*p, *f为*p的双亲结点
p=T; f=NULL; //初始化
while(p){
if(key==p->data){
break;
}
f=p;
if(p->data>key){
p=p->lchild; //在左子树中查找
}else{
p=p->rchild; //在右子树中查找
}
}
if(!p){
return; //找不到要删除的结点
}
/*------考虑3种情况实现p所指子树内部的处理:*p 左右子树均不空、无右子树、无左子树-------*/
BSTree q, s;
//1.被删结点左右子树都非空
if((p->lchild) && (p->rchild)){
q=p;
s=p->lchild;
//在*p的左紫苏中查找器直接前驱结点,即最右下的结点
while(s->rchild){
q=s;
s=s->rchild;//向右到尽头
}
p->data=s->data; //s指向被删除结点的前驱
if(q!=p){
q->rchild=s->lchild;//重接*q的右子树
}else{
q->lchild=s->lchild;//接*q的左子树
}
delete s;
return;
} else if(!p->rchild){
//被删除结点无右子树,重接左子树
q=p;
p=p->lchild;
} else if(!p->lchild){
//被删除结点无左子树,重接右子树
q=p;
p=p->rchild;
}
if(!f){
T=p;
} else if(q==f->lchild){
f->lchild=p;
}else{
f->rchild=p;
}
delete p;
}
上述操作的完整代码实现如下:
#include<stdio.h>
#define MAXSIZE 100
using namespace std;
typedef struct BSTNode{
int data; //数据域
struct BSTNode *lchild,*rchild; //左右孩子指针域
}BSTNode,*BSTree;
//二叉排序树的递归查找
BSTree SearchBST(BSTree &T, int key){
//在根指针T所指的二叉树中查找关键字等于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, int e){
if(!T){
BSTNode *s=new BSTNode;
s->data=e;
s->lchild=NULL;
s->rchild=NULL;
T=s;
} else if(e<T->data){
InsertBST(T->lchild, e);
}else if(e>T->data){
InsertBST(T->rchild, e);
}
}
//二叉排序树的创建
void CreateBST(BSTree &T){
T=NULL;
int e;
printf("请输入根点元素值(-1表示输入结束):");
scanf("%d", &e);
//输入-1表示结束
while(e!=-1){
InsertBST(T, e);
printf("请输入结点元素值(-1表示输入结束):");
scanf("%d", &e);
}
}
//从二叉排序树中删除关键字等于key的结点
void DeleteBST(BSTree &T, int key){
BSTree p, f; //查找关键字等于key的结点*p, *f为*p的双亲结点
p=T; f=NULL; //初始化
while(p){
if(key==p->data){
break;
}
f=p;
if(p->data>key){
p=p->lchild; //在左子树中查找
}else{
p=p->rchild; //在右子树中查找
}
}
if(!p){
return; //找不到要删除的结点
}
/*------考虑3种情况实现p所指子树内部的处理:*p 左右子树均不空、无右子树、无左子树-------*/
BSTree q, s;
//1.被删结点左右子树都非空
if((p->lchild) && (p->rchild)){
q=p;
s=p->lchild;
//在*p的左紫苏中查找器直接前驱结点,即最右下的结点
while(s->rchild){
q=s;
s=s->rchild;//向右到尽头
}
p->data=s->data; //s指向被删除结点的前驱
if(q!=p){
q->rchild=s->lchild;//重接*q的右子树
}else{
q->lchild=s->lchild;//接*q的左子树
}
delete s;
return;
} else if(!p->rchild){
//被删除结点无右子树,重接左子树
q=p;
p=p->lchild;
} else if(!p->lchild){
//被删除结点无左子树,重接右子树
q=p;
p=p->rchild;
}
if(!f){
T=p;
} else if(q==f->lchild){
f->lchild=p;
}else{
f->rchild=p;
}
delete p;
}
//中序遍历二叉树
void InOrderTraveTree(BSTree &T){
if(T){
InOrderTraveTree(T->lchild);
printf("%d ", T->data);
InOrderTraveTree(T->rchild);
}
}
int main(){
BSTree T;
CreateBST(T);
printf("中序遍历二叉排序树:\n");
InOrderTraveTree(T);
printf("\n");
int key;
printf("输入要查找的结点值:");
scanf("%d", &key);
BSTree p=SearchBST(T, key);
if(!p){
printf("查找失败.\n");
}else{
printf("查找成功.\n");
}
/*int insertKey;
printf("输入要插入的结点值:");
scanf("%d", &insertKey);
InsertBST(T, insertKey);
printf("插入后遍历结果:\n");
InOrderTraveTree(T);
printf("\n"); */
int delKey;
printf("请输入要删除的key:");
scanf("%d", &delKey);
DeleteBST(T, delKey);
printf("删除后遍历的结果:\n");
InOrderTraveTree(T);
}