当表插入、删除操作频繁时,为维护表的有序性,需要移动表中很多记录。
改用动态查找表——几种特殊的树——表结构在查找过程中动态生成。
对于给定值key,若表中存在,则成功返回;否则,插入关键字等于key的记录。
二叉排序树
二叉排序树(Binary Sort Tree)又称为二叉搜索树、二叉查找树。
二叉排序树定义
定义:
二叉排序树或是空树,或是满足如下性质的与叉树:
① 若其左子树非空,则左子树上所有结点的值均小于根结点的值;
② 若其右子树非空,则右子树上所有结点的值均大于等于根结点的值;
③ 其左右子树本身又各是一棵二叉排序树。
性质:
中序遍历非空的二叉排序树所得到的数据元素序列是一个按关键字排列的递增有序序列。
二叉排序树查找——递归算法
【算法步骤】
若查找的关键字等于根结点,成功
否则:
若小于根结点,查其左子树
若大于根结点,查其右子树
在左右子树上的操作类似
【算法思想】
(1)若二叉排序树为空,则查找失败,返回空指针。
(2)若二叉排序树非空,将给定值key与根结点的关键字T->data.key进行比较:
① 若key等于T->data.key,则查找成功,返回根结点地址;
② 若key小于T->data.key,则进一步查找左子树;
③ 若key大于T->data.key,则进一步查找右子树。
二叉排序树的存储结构
typedef struct{
KeyType key;//关键字项
InfoType otherInfo;//其他数据域
}ElemType;//定义数据域
typedef struct BSTNode{
ElemType data;//数据域
struct BSTNode *lchild,*rchild;//左右孩子指针
}BSTNode,*BSTree;
BSTree T;//用BSTree指针类型定义一个二叉排序树T,这个T指向二叉排序树的根结点
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);//在右子树中继续查找
}
返回值类型是指向这个结点的指针
二叉排序树的查找分析
二叉排序树上查找某关键字等于给定值的结点过程,其实就是走了一条从根到该结点的路径。
比较的关键字次数=此结点所在层次数
最多的比较次数=树的深度
含有n个结点的二叉排序树的平均查找长度ASL和树的形态有关。
最好情况:
ASL=log2(n+1)-1;
树的深度为:⌊log2n⌋+1;
与折半查找中的判定树相同。(形态比较均衡)
时间复杂度:O(log2n)
最坏情况:
插入的n个元素从开始就有序,变成单支树的形态。
此时树的深度为n,ASL=(n+1)/2
查找效率与顺序查找情况相同,
时间复杂度:O(n)
提高形态不均衡的二叉排序树的查找效率办法:
做“平衡化”处理,即尽量让二叉树的形状均衡。
推出平衡二叉树。
二叉排序树的操作
插入
【思想】
① 若二叉排序树为空,则插入结点作为根结点插入到空树中
② 否则,继续在其左、右子树上查找:
树中已有,不再插入;
树中没有,查找直至某个叶子结点的左子树或右子树为空为止,则插入结点应为该叶子结点的左孩子或右孩子。
插入的元素一定在叶结点上。
生成
从空树出发,经过一系列的查找、插入操作之后,可生成一株二叉排序树。
【思想】
① 一个无序序列可通过构造二叉排序树而变成一个有序序列。构造树的过程就是对无序序列进行排序的过程。
② 插入的结点均为叶子结点,故无需移动其他结点。相当于在有序序列上插入记录而无需移动其他记录。
不同插入次序的序列生成不同形态的二叉排序树:
二叉排序树的形态不一样,查找效率也不一样。
删除
【注意】
① 从二叉排序树中删除一个结点,不能把以该结点为根的子树都删去,只能删掉该结点,并且还应保证删除后所得的二叉树仍然满足二叉排序树的性质不变。
② 由于中序遍历二叉排序树可以得到一个递增有序的序列。那么,在二叉排序树中删去一个结点相当于删去有序序列中的一个结点。
● 将因删除结点而断开的二叉链表重新链接起来;
● 防止重新链接后树的高度增加。
不同情况的删除方法:
(1) 被删除的结点是叶子结点:直接删去该结点。
其双亲结点中相应指针域的值改为“空”。
(2) 被删除的结点只有左子树或者只有右子树:用其左子树或者右子树替换它(结点替换)。
其双亲结点的相应指针域的值改为"指向被删除结点的左子树或右子树” 。
(3) 被删除的结点既有左子树,也有右子树。
① 以其中序前趋值替换之(值替换),然后再删除该前趋结点。前趋是左子树中最大的结点。
② 也可以用其后继替换之,然后再删除该后继结点。后继是右子树中最小的结点。
平衡二叉树
平衡二叉树(balanced binary tree)
又称AVL树(Adelson-Velskii and Landis)
平衡二叉树定义
定义:
一棵平衡二叉树或者是空树, 或者是具有下列性质的二叉排序树:
① 左子树与右子树的高度之差的绝对值小于等于1;
② 左子树和右子树也是平衡二叉排序树。
平衡因子(BF):
为了方便起见,给每个结点附加一个数字,给出该结点左子树子与右子树的高度差,这个数字称为结点的平衡因子(BF)。
平衡因子=结点左子树的高度-结点右子树的高度
根据平衡二叉树的定义,平衡二叉树上所有结点的平衡因子只能是-1、0、1。
对于一棵有n个结点的AVL树, 其高度保持在O(log2n)数量级,ASL也保持在O(log2n)量级。
平衡调整方法
当我们在一个平衡二叉排序树上插入一个结点时,有可能导致失衡,即出现平衡因子绝对值大于1的结点,如:2、-2。
如果在一棵AVL树中插入一个新结点后造成失衡,则必须重新调整树的结构,使之恢复平衡。
不止一个失衡结点时,找最小失衡子树的根结点作为失衡结点:
以“7”结点为根结点的子树有5个结点,以“16”结点为根结点的子树有3个结点,所有以“16”结点为失衡结点。
平衡调整的四种类型
A:失衡结点
B:A结点的孩子,C结点的双亲
C:插入新结点的子树
调整原则:
① 降低高度
② 保持二叉排序树性质
找到失衡二叉排序树的大中小结点,根结点是中间大小,根结点的左子树结点是小的,右子树结点是大的。
AVL树LL调整:
【调整过程】
① B结点带左子树α一起上升;
② A结点成为B的右孩子;
③ 原来B结点的右子树作为A的左子树。
例:
AVL树RR调整:
【调整过程】
① B结点带右子树β一起上升;
② A结点成为B的左孩子;
③ 原来B结点的左子树α作为A的右子树。
例:
AVL树LR调整:
【调整过程】
① C结点穿过A、B结点上升;
② B结点成为C的左孩子,
A结点成为C的右孩子;
③ 原来C结点的左子树β作为B的右子树,
原来C结点的右子树γ作为A的左子树。
例:
AVL树RL调整:
例: