目录
一. 前言
二叉排序树又称为二叉搜索树,二叉查找树。
二叉排序树可以是一个空树,也可以是一个满足下面性质的二叉树:
1)若其左子树非空,则左子树上所有结点的值都小于根结点的值。
2)若其右子树非空,则右子树上所有结点的值均大于等于根结点的值。
3)其左右子树本身又是一棵二叉排序树。
同时,我们若使用中序遍历的方法来遍历一个非空的二叉排序树,那么得到的数据元素序列就是一个按关键字排列的递增有序序列。
二. 二叉排序树的结构定义和查找
下面我们来看下二叉排序树的结构定义:
typedef struct{
KeyType key; //定义关键字
InfoType other; //其它数据域
}ElemType;
typedef struct BSTnode{
ElemType data; //数据域
struct BSTnode* lchild,*rchild; //左右孩子指针
}BSTnode,*BSTree;
BSTree T; //定义二叉排序树
在定义好了二叉排序树后,我们就可以进行在上面进行查找操作了。
利用二叉排序树来进行查找算法的主要思路为:
1)首先判断二叉排序树是否为空,如果为空,则查找失败,返回空指针。
2)如果不为空,那么就将给定的值key来跟根结点的关键字T->data进行比较:
若key等于T->data.key,则表示查找成功,返回根结点地址。
若key小于T->data.key,则继续根据上面步骤查找左子树;因为左子树存储的都是比根结点小的数据。
若key大于T->data.key,则继续查找右子树。
使用代码实现如下所示:
BSTree SearchBST(BSTree T,KeyType key){
if((!T)||key==T->data.key) return T; //如果为空或者已经找到就返回这个根结点地址
else if(key<T->data.key)
return SearchBST(T->lchild,key); //在此根结点左子树中继续查找
else return SearchBST(T->rchild,key); //在右子树中继续查找
}
通过分析,我们可以知道二叉排序树上查找某个关键字等于给定值的结点过程,其实就是走了一条从根到该结点的路径,也就是说,我们要查找一个关键字,需要比较的次数就等于此结点所在的层次数。
三. 二叉排序树的操作--插入
该操作的主要思路为:首先判断二叉排序树是否为空,如果为空,则插入结点作为根结点插入到空树中。若不为空,则执行我们上面所学的查找操作,查找这个根结点的左右子树,如果要插入的结点在树中已经存在,就不再插入,如果树中没有,就插入到叶子节点的左孩子或者右孩子。
四. 二叉排序树的操作--生成
该操作的主要思路为:从空树出发,经过一系列的查找,插入操作之后,就可以生成一棵二叉排序树。
一个无序序列就可以通过生成二叉序列而使它成为一个有序序列。并且插入的结点都为叶子结点,无需移动其它结点,就相当于在有序序列上插入记录而无需移动其它记录。
当我们关键字的输入顺序不同的时候,就会导致建立的二叉排序树也不同。
五. 二叉排序树的操作--删除
从二叉排序树中删除一个结点后,还应保证删除后的二叉树依旧满足二叉排序树的性质。所以就需要做一些调整。
如果我们删除的结点是叶子结点,那么因为它没有左右子树,那我们就可以直接删去它。
如果我们删除的结点是只有左子树,或者只有右子树,那么就用它的左子树或者右子树代替它。再将双亲结点的相应指针域改为指向被删除结点的左子树或者右子树就可以了。
如果我们删除的结点既有左子树又有右子树,那么我们首先就得对这个二叉排序树进行中序遍历,用这个被删除结点在中序遍历结果中的前驱来替换它,这个前驱就是左子树中最大的结点。
也可以用它的后继来替换它,这个后继就是右子树中最小的结点。