二叉排序树或者是一棵空树,或者是具有下列性质的二叉树:
(1)若左子树不空,则左子树上所有结点的值均小于或等于它的根节点的值;
(2)若右子树不空,则右子树上所有结点的值均大于或等于它的根结点的值;
(3)左、右子树也分别为二叉排序树;
以下为二叉排序树的实例和结点结构
1、找出被插结点的父亲结点。
以下为二叉排序树的实例和结点结构
//二叉排序树的结点结构
typedef struct Node{
ElemType val;
struct Node *LChild,*RChild;
}Node;
二叉排序树的插入
1、找出被插结点的父亲结点。
2、判断被插结点是其父亲结点的左、右儿子。将被插结点作为叶子结点插入。
3、若二叉树为空。则首先单独生成根结点。
1、若*p结点为叶子结点,即PL(左子树)和PR(右子树)均为空树。由于删去叶子结点不破坏整棵树的结构,则可以直接删除此子结点。
2、若*p结点只有左子树PL或右子树PR,此时只要令PL或PR直接成为其双亲结点*f的左子树(当*p是左子树)或右子树(当*p是右子树)即可,作此修改也不破坏二叉排序树的特性。
3、若*p结点的左子树和右子树均不空。在删去*p之后,为保持其它元素之间的相对位置不变,令*p的直接前驱(或直接后继)替代*p,然后再从二叉排序树中删去它的直接前驱(或直接后继)-即让*f的左子树(如果有的话)成为*p左子树的最左下结点(如果有的话),再让*f成为*p的左右结点的父结点。
以下为完整程序
//在二叉排序树中插入一个关键字为value的结点
int Insert(Node *root,int value){
Node *p=root,*q=NULL,*par=NULL;
int mark=0;
while(p!=NULL&&mark==0){//找到value应插入的父节点
par=p;
if(p->val==value){
mark=1;
}else if(p->val>value){
p=p->LChild;
}else if(p->val<value){
p=p->RChild;
}
}
if(mark==1) return 0;//存在value则不插入
q=(Node *)malloc(sizeof(Node));
q->val=value;
q->LChild=q->RChild=NULL;
if(root==NULL){
root=q;
}else if(par->val>q->val){//判断插入其左右子树
par->LChild=q;
}else{
par->RChild=q;
}
return 1;
}
二叉排序树的查找,像其他树的查找一样遍历结点
//查找关键字为key的结点,返回指向该结点的指针
Node *Search(Node *root,int key){
Node *p=NULL;
if(root==NULL){
return NULL;
}
p=root;
while(p){
if(p->val==key){
return p;
}else if(p->val>key){//当前节点的值大于key则去结点的左子树查找
p=p->LChild;
}else{
p=p->RChild;
}
}
return p;
}
二叉排序树的删除
1、若*p结点为叶子结点,即PL(左子树)和PR(右子树)均为空树。由于删去叶子结点不破坏整棵树的结构,则可以直接删除此子结点。
2、若*p结点只有左子树PL或右子树PR,此时只要令PL或PR直接成为其双亲结点*f的左子树(当*p是左子树)或右子树(当*p是右子树)即可,作此修改也不破坏二叉排序树的特性。
3、若*p结点的左子树和右子树均不空。在删去*p之后,为保持其它元素之间的相对位置不变,令*p的直接前驱(或直接后继)替代*p,然后再从二叉排序树中删去它的直接前驱(或直接后继)-即让*f的左子树(如果有的话)成为*p左子树的最左下结点(如果有的话),再让*f成为*p的左右结点的父结点。
//从二叉排序树中删除值为value的结点并重新连接它的左或右子树
int Delete(Node *root,int value){
Node *s,*p,*q;
p=Search(root,value);//查找value的结点
if(p==NULL) return 1;//没有找到
if(!p->RChild){//右子树空则只需重接它的左子树
q=p;
p=p->LChild;
free(p);
}else if(!p->LChild){//左子树空则只需重接它的右子树
q=p;
p=p->RChild;
free(p);
}else{//左右子树均不空
q=p;
s=p->RChild;
while(s->LChild){//转右,然后向左到尽头
q=s;
s=s->LChild;
}
p->val=s->val;//s指向被删结点的前驱
if(q!=p){
q->LChild=s->RChild;
}else{
q->LChild=s->LChild;
}
free(s);
}
return 0;
}
以下为完整程序
#include<stdio.h>
#define N 100
typedef int ElemType;
//二叉排序树的结点结构
typedef struct Node{
ElemType val;
struct Node *LChild,*RChild;
}Node;
Node *BitRepTr;
//查找关键字为key的结点,返回指向该结点的指针
Node *Search(Node *root,int key){
Node *p=NULL;
if(root==NULL){
return NULL;
}
p=root;
while(p){
if(p->val==key){
return p;
}else if(p->val>key){//当前节点的值大于key则去结点的左子树查找
p=p->LChild;
}else{
p=p->RChild;
}
}
return p;
}
//在二叉排序树中插入一个关键字为value的结点
int Insert(Node *root,int value){
Node *p=root,*q=NULL,*par=NULL;
int mark=0;
while(p!=NULL&&mark==0){//找到value应插入的父节点
par=p;
if(p->val==value){
mark=1;
}else if(p->val>value){
p=p->LChild;
}else if(p->val<value){
p=p->RChild;
}
}
if(mark==1) return 0;//存在value则不插入
q=(Node *)malloc(sizeof(Node));
q->val=value;
q->LChild=q->RChild=NULL;
if(root==NULL){
root=q;
}else if(par->val>q->val){//判断插入其左右子树
par->LChild=q;
}else{
par->RChild=q;
}
return 1;
}
//从二叉排序树中删除值为value的结点并重新连接它的左或右子树
int Delete(Node *root,int value){
Node *s,*p,*q;
p=Search(root,value);//查找value的结点
if(p==NULL) return 1;//没有找到
if(!p->RChild){//右子树空则只需重接它的左子树
q=p;
p=p->LChild;
free(p);
}else if(!p->LChild){//左子树空则只需重接它的右子树
q=p;
p=p->RChild;
free(p);
}else{//左右子树均不空
q=p;
s=p->RChild;
while(s->LChild){//转右,然后向左到尽头
q=s;
s=s->LChild;
}
p->val=s->val;//s指向被删结点的前驱
if(q!=p){
q->LChild=s->RChild;
}else{
q->LChild=s->LChild;
}
free(s);
}
return 0;
}
//中序遍历二叉排序树
void MidOrder(Node *root){
if(root!=NULL){
MidOrder(root->LChild);
printf("%d ",root->val);
MidOrder(root->RChild);
}
}
int main(){
Node *root,*p;
int k,i,val,n,num[N];
printf("首先建立二叉排序树\n");
printf("请输入结点个数\n");
scanf("%d",&n);
if(n<1){
return -1;
}
root=(Node *)malloc(sizeof(Node));
printf("输入各节点的关键字值,以空格间隔\n");
scanf("%d",&num[0]);
root->val=num[0];
root->LChild=NULL;
root->RChild=NULL;
for(i=1;i<n;i++){
scanf("%d",&num[i]);
Insert(root,num[i]);
}
printf("对二叉排序树进行的中序遍历结果如下:\n");
MidOrder(root);
printf("\n");
printf(" 1-----------查找\n");
printf(" 2-----------查找\n");
printf(" 3-----------查找\n");
printf("请选择(1-3):");
scanf("%d",&k);
switch(k){
case 1:
printf("选择了查找\n");
printf("请输入要查找的值:");
scanf("%d",&val);
if(Search(root,val)!=NULL){
printf("找到了\n");
}else{
printf("没有找到\n");
}
break;
case 2:
printf("选择了插入\n");
printf("请输入要插入的值:");
scanf("%d",&val);
if(Insert(root,val)!=0){
printf("插入成功\n");
printf("对新二叉排序树进行中序遍历的结果如下:\n");
MidOrder(root);
printf("\n");
}else{
printf("插入失败,值为%d的结点已存在\n",val);
}
break;
case 3:
printf("选择了删除\n");
printf("请输入要删除的值:");
scanf("%d",&val);
if(Delete(root,val)!=1){
printf("删除成功\n");
printf("对新二叉排序树进行中序遍历的结果如下:\n");
MidOrder(root);
printf("\n");
}else{
printf("删除失败,值为%d的结点不存在\n",val);
}
break;
default:
printf(" 1-----------查找\n");
printf(" 2-----------查找\n");
printf(" 3-----------查找\n");
break;
}
}