定义:
二叉排序树或是空树,或是满足如下性质的二叉树:
1,若其左子树非空,则左子树上所有的结点的值均小于根结点的值;
2,若其右子树非空,则右子树上所有的结点的值均大于等于根结点的值;
3,其左右子树本身又各是一棵二叉排序树
例如:
这就是一棵二叉排序树,左子树小于根结点,右子树大于等于根结点,再比如下面:
这就不是一个二叉排序树了,因为左子树上面的48大于根结点45
二叉排序树的特点:
中序遍历下面二叉排序树
得到的结果是:3 12 24 37 45 53 61 78 90 99
所以:中序遍历非空的二叉排序树所得到的数据元素序列是一个按关键字排列的递增有序的序列.
二叉排序树的操作-查找
步骤:
若查找的关键字等于根结点,成功
否则:
若小于根结点,查其左子树
若大于根结点,查其右子树
在左右子树上再进行同样的操作
举例:
要查找24,首先24和根结点45比较,小于45,则查找45的左子树12,再比较,24大于12,则查找12的右子树37,再比较,24小于37,则查找37的左子树24,发现相等,查找成功
那如果要查找的是23,同样进行上面的操作,找到24,比较发现23小于24,则查找24的左子树,24的左子树为空,则查找失败.结束
二叉排序树的存储结构
typedef struct{
KeyType key;//关键字项
InfoType otherinfo;//其它数据域
}ElemType;
typedef struct BSTNode{
ElemType data; //数据域
struct BSTNode *lchild, *rchild; //左右孩子指针
}BSTNode, *BSTree;
BSTree T; //定义二叉排序树T
二叉排序树的递归查找
算法思想:
1,若二叉排序树为空,则查找失败,返回空指针.
2,若二叉排序树非空,将给定值key与根结点的关键字T->data.key进行比较:
若key等于T->data.key,则查找成功,返回根结点地址;
若key小于T->data.key,则进一步查找左子树;
若key大于T->data.key,则进一步查找右子树;
二叉排序树的操作-插入
若二叉排序树为空,则插入结点作为根结点插入到树中
否则,继续在其左,右子树上查找
树中已有,不再插入
树中没有
查找直至某个结点的左子树或右子树为空为止,
则插入结点应为该结点的左孩子或右孩子.
举个例子:
上面二叉排序树,要插入一个元素40,其过程为:
首先和根结点45比较,小于45,查找其左子树12,再比较,大于12,查找其右子树37,再比较,大于37,查找其右子树,发现为空,此时就可以插入到37的右子树
二叉排序树的操作-生成
从空树出发,经过一系列的查找,插入操作之后,可生成一棵二叉排序树.
实际上就是对一个空树进行二叉排序树的插入操作,最终生成一棵新的二叉排序树
一个无序序列可通过构造二叉排序树而变成一个有序序列.构造树的过程就是对无序序列进行排序的过程.
插入的结点均为叶子结点,故无需移动其他结点,相当于有序序列上插入记录而无需移动其他记录
但是:
关键字的输入顺序不同,建立的二叉排序树不同.
二叉排序树的操作-删除
从二叉排序树中删除一个结点,不能把以该结为根的子树都删除,只能删掉该结点,并且还应保证删除后所得的二叉树仍然满足二叉排序树的性质不变
由于中序遍历二叉排序树可以得到一个递增有序的序列.那么,在二叉排序树中删去一个结点相当于删去有序序列中的一个结点.
将因删除结点而断开的二叉链表重新链接起来
防止重新链接后树的高度增加(树的高度决定查找的复杂度)
所以,删除的操作要分为下面几种情况:
1,被删除的结点是叶子结点:直接删去该结点(直接修改其双亲结点相应的指针域修改为空 )
2,被删除的结点只有左子树或者只有右子树,用其左子树或者右子树替换它(修改其双亲域指针,如果该结点只有左子树,修改其双亲域指针为该结点的左子树,如果该结点只有右子树,修改其双亲域指针为该结点的右子树)
要删除37,把37的左子树24直接连到12的右子树上面.得到:
3,被删除的结点既有左子树,也有右子树
①以其中序前趋值替换之(值替换),然后再删除该前趋结点.前趋是左子树中最大的结点
②也可以用其后继替换之,然后再删除该后继结点.后继是右子树中最小的结点
这里可以用12的前趋中最大值3来替换12,然后删去3,删除3时也要分以上三种情况:
也可以用12的后继中最小值24替换12,然后再删掉24,删除24时也要分以上三种情况:
以下就是二叉排序树的生成,以及增删查的详细代码:
#include <stdio.h>
#include <stdlib.h>
#define MAXINT 10000
typedef struct BSTnode{
int data;//这里为了方便,直接用int,没有用结构体.
struct BSTnode* lchild;
struct BSTnode* rchild;
}BSTnode,*BSTree;
BSTree Parent;//设置全局变量,用来接收查找到的某个结点的双亲地址
int TempInt = MAXINT;//全局变量,存储二叉排序树中的最小节点值
//BSTree MinNode;//全局变量,存储二叉排序树中的最小节点地址
BSTree SearchBST(BSTree T, int m)//二叉排序树的递归查询,得到值的地址
{
if(!T || T->data == m)
{
return T;
}
else if(m < T->data)
{
if(T->lchild->data == m)Parent = T;
return SearchBST(T->lchild, m);
}
else
{
if(T->rchild->data == m)Parent = T;
return SearchBST(T->rchild, m);
}
}
void FindMinBST(BSTree T)//中序遍历二叉排序树,找到该树中最小值,以及该结点的地址
{
if(T == NULL)return;
else
{
FindMinBST(T->lchild);
if(T->data < TempInt)
{
TempInt = T->data;
//MinNode = T;
}
FindMinBST(T->rchild);
}
}
void AddBST(BSTree* T, int m)//二叉排序树的递归添加元素
{
if(!(*T))
{
*T = malloc(sizeof(BSTnode));
(*T)->data = m;
(*T)->lchild = NULL;
(*T)->rchild = NULL;
}
else if(m < (*T)->data)
{
AddBST(&(*T)->lchild, m);
}
else
{
AddBST(&(*T)->rchild, m);
}
}
void DelBST(BSTree* T, int m)//删除元素
{
BSTree temp = SearchBST(*T, m);//用一个临时变量接收,查询到的m对应的结点地址
if(!temp)//如果temp为空,说明没有该结点
{
printf("你要删除的结点不存在,请重新输入:>");
return;
}
if(!temp->lchild && !temp->rchild)//第一种情况,如果该结点为叶子结点,那么直接删除
{
free(temp);
if(m < Parent->data)Parent->lchild = NULL;
else Parent->rchild = NULL;
}
else if(!temp->lchild && temp->rchild)//第二种情况,如果左孩子为空,右孩子不为空
{
if(m < Parent->data)Parent->lchild = temp->rchild;
else Parent->rchild = temp->rchild;
free(temp);
}
else if(temp->lchild && !temp->rchild)//第二种情况,如果右孩子为空,左孩子不为空
{
if(m < Parent->data)Parent->lchild = temp->lchild;
else Parent->rchild = temp->lchild;
free(temp);
}
else//第三种情况,左右孩子都不为空(找到左孩子中的最大值或者右孩子中的最小值),这里找右孩子的最小值
{
FindMinBST(temp->rchild);//找以右孩子为根结点的二叉排序树的最小结点
DelBST(T, TempInt);//再删除找到的这个最小值的结点
temp->data = TempInt;//用找到的最小值替换要删除的值
}
}
void creatBST(BSTree* T)//创建二叉排序树,实际上就是给一个空树添加元素
{
int i;
while(i)
{
printf("请依次输入数字序列,输入完毕以0结束:>");
scanf("%d",&i);
if(i == 0)break;
AddBST(T, i);
}
}
void printBST(BSTree T)//中序输出二叉排序树,得到的是一个递增数列
{
if(T == NULL)return;
else
{
printBST(T->lchild);
printf("%d ",T->data);
printBST(T->rchild);
}
}
int main()
{
BSTree T = NULL;//定义二叉排序树T
creatBST(&T);//创建二叉排序树
printBST(T);//输出创建好的二叉排序树
printf("\n");
DelBST(&T, 23);//删除指定元素
printBST(T);//再输出此时的二叉排序树
return 0;
}