几种特殊的树
当表插入、删除操作频繁时,为维护表的有序性,需要移动表中很多记录。 改用动态查找表——几种特殊的树,表结构在查找过程中动态生成。 对于给定值key,若表中存在,则成功返回;否则,插入关键字等于key的记录。
几种特殊的树:
二叉排序树
二叉排序树定义
二叉排序树(Binary Sort Tree)又称为二叉搜索树、二叉查找树,它是一种对排序和查找都很有用的特殊二叉树。 二叉排序树或是空树,或是满足如下性质的二叉树: (1)若其左子树非空,则左子树上所有结点的值均小于根节点的值; (2)若其右子树非空,则右子树上所有结点的值均大于等于根节点的值; (3)其左右子树本身又各是一棵二叉排序树。
二叉排序树实例
若中序遍历图(a),则可得到一个按数值大小排序的递增序列: 3, 12, 24, 37, 45, 53, 61, 78, 90, 100 若中序遍历图(b),则可得到一个按字符大小排序的递增序列: CAO, CHEN, DING, DU, LI, MA, WANG, XIA,ZHAO
可以得出二叉排序树的性质:中序遍历非空的二叉排序树所得到的数据元素序列是一个按关键字排列的递增有序序列。
二叉排序树的操作-查找思想
- 若查找的关键字等于根节点,成功
- 否则
- 在左右子树上的操作类似。
二叉排序树的二叉链表存储表示
typedef struct
{
KeyType key;
InfoType otherinfo;
}ElemType;
typedef struct BSTNode
{
ElemType data;
struct BSTNode *lchild,*rchild;
}BSTNode,*BSTree;
二叉排序树的递归查找
算法思想
(1)若二叉排序树为空,则查找失败,返回空指针。 (2)若二叉排序树非空,将给定值key与根节点的关键字T->data.key进行比较: ① 若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);
}
二叉排序树的查找分析
二叉排序树上查找某关键字等于给定值的结点过程,其实就是走了一条从根到该结点的路径。 比较的关键字次数 = 此结点所在层次数。 最多的比较次数 = 树的深度。
二叉排序树的平均查找长度
含有n个结点的二叉排序树的平均查找长度和树的形态有关。
最好情况:初始序列{45, 24, 53, 12, 37, 93} ,ASL =log2(n+1) -1;树的深度为log2n+1;与折半查找中的判定树相同。(形态比较均衡):O(log2n)
最坏情况:初始序列{12, 24, 37, 45, 53, 93},插入的n个元素从一开始就有序,编程单支树的形态!此时树的深度为n,ASL=(n+1) / 2,查找效率与顺序查找情况相同:O(n)。 那么问题来了:如何提高形态不均衡的二叉排序树的查找效率? 解决办法:做“平衡化”处理,即尽量让二叉树的形态均衡! —— 平衡二叉树
二叉排序树的操作-插入
- 若二叉排序树为空,则插入结点作为根节点插入到空树中;
- 否则,继续在其左、右子树上查找;
- 树中已有,不再插入,
- 树中没有
- 查找直至某个叶子结点的左子树或右子树为空为止,则插入结点应为该叶子结点的左孩子或右孩子。
插入的元素一定在叶结点上!
void InsertBST(BSTree &T,ElemType e}
{
if (!T)
{
S=new BSTNode;
S->data=e;
S->lchild=S->rchild=NULL;
T=S;
}
else if (e.key<T->data.key)
InsertBST(T->lchild, e );
else if (e.key> T->data.key)
InsertBST(T->rchild, e);
}
二叉排序树插入的基本过程是查找,所以时间复杂度同查找一样,是 O(log2n)。
二叉排序树的操作-生成
从空树出发,经过一系列的查找、插入操作之后,可生成一棵二叉排序树。
一个无序序列可通过构造二叉排序树而变成一个有序序列。构造树的过程就是对无序序列进行排序的过程。
插入的结点均为叶子结点,故无需移动其他结点。相当于在有序序列上插入记录而无需移动其他记录。
但是:关键字的输入顺序不同,会建立不同二叉排序树。
void CreatBST(BSTree &T)
{
T=NULL;
cin>>e;
while(e.key!=ENDFLAG)
{
InsertBST(T,e);
cin>>e;
}
}
设关键字的输入次序为: 45,24,53,45, 12,24,90, 按上述算法生成的二叉排序树的过程如图 所示。 但是如果打乱顺序,生成的二叉排序树就会有很大差别。
二叉排序树的操作-删除
从二叉排序树中删除一个结点,不能把以该结点为根的子树都删去,只能删掉该结点,并且还应保证删除后所得的二叉树仍然满足二叉排序树的性质不变。
由于中序遍历二叉排序树可以得到一个递增有序的序列。那么,在二叉排序树中删去一个结点相当于删去有序序列中的一个结点。
- 将因删除结点而断开的二叉链表重新链接起来。
- 防止重新链接后树的高度增加。
(1)被删除的结点是叶子结点:直接删去该结点。 (2)被删除的结点只有左子树或者右子树,用其左子树或者右子树替换它(结点替换)。 其双亲结点的相应指针域的值改为“指向被删除结点的左子树或右子树”。 (3)被删除的结点既有左子树,也有右子树
- 以其中序前驱值替换之(值替换),然后再删除该前趋结点。前趋是左子树中最大的结点。
- 也可以用其后继替换之,然后再删除该后继结点。后继是右子树中最小的结点。
void DeleteBST(BSTree &T,KeyType key)
{
p=T;f=NULL;
while (p)
{
if(p->data.key==key) break;
f=p;
if(p->data.key>key) p=p->lchild;
else p=p->rchild;
}
if (!p) return;
if ((p->lchild) && (p->rchild))
{
q=p; s=p->lchild;
while (s->rchild)
{
q=s; s=s->rchild;
}
p->data=s->data;
if(q!=p) q->rchild=s->lchild;
else q->lchild=s->lchild;
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 q;
}
平衡二叉树(balanced binary tree)
- 又称AVL树(Adelson-Velskii and Landis)。
- 一棵平衡二叉树或者是空树,或者是具有下列性质的二叉排序树:
① 左子树与右子树的高度之差的绝对值小于等于1; ② 左子树和右子树也是平衡二叉排序树。 - 为了方便起见,给每个结点附加一个数字,给出该结点左子树与右子树的高度差。这个数字称为结点的平衡因子(BF)。
平衡因子 = 结点左子树的高度 - 结点右子树的高度 - 根据平衡二叉树的定义,平衡二叉树上所有结点的平衡因子只能是-1、0,或1。
- 对于一棵有n个结点的AVL树,其高度保持在O(log2n)数量级,ASL也保持在O(log2n)量级。
平衡树的生成过程
失衡二叉排序树的分析与调整
当我们在一个平衡二叉排序树上插入一个结点时,有可能导致失衡,即出现平衡因子绝对值大于1的结点,如:2、-2。
如果在一棵AVL树中插入一个新结点后造成失衡,则必须重新调整树的结构,使之恢复平衡。
平衡调整的四种类型
A:失衡结点,不止一个失衡结点时,为最小失衡子树的根节点。 B:A结点的孩子,C结点的双亲。 C:插入新结点的子树。
失衡树的调整
调整原则:1)降低高度;2)保持二叉排序树性质。
LL型
- B结点带左子树BL一起上升;
- A结点成为B的右孩子;
- 原来B结点的右子树BR作为A的左子树。
RR型
- B结点带右子树BR一起上升;
- A结点成为B的左孩子;
- 原来B结点的左子树BL作为A的右子树。
LR型
- C结点穿过A、B结点上升;
- B结点成为C的左孩子,A结点成为C的右孩子;
- 原来C结点的左子树CL作为B的右子树,原来C结点的右子树CR作为A的左子树。
RL型
平衡二叉树的插入
在平衡的二叉排序树BBST上插入一个新的数据元素e的递归算法可描述如下。 ① 若BBST为空树,则插入一个数据元素为e的新结点作为BBST的根结点,树的深度增1。 ② 若e的关键字和BBST的根结点的关键字相等,则不进行插入。 ③ 若e的关键字小于BBST的根结点的关键字,而且在BBST的左子树中不存在和e有相同关键字的结点,则将e插入在BBST的左子树上,并且当插入之后的左子树深度增加(+1)时,分别就下列不同情况处理之: ? BBST 的根结点的平衡因子为-1(右子树的深度大于左子树的深度):则将根结点的平衡因子更改为0, BBST的深度不变; ? BBST的根结点的平衡因子为0(左、右子树的深度相等):则将根结点的平衡因子更改为1, BBST的深度增1; ? BBST的根结点的平衡因子为1(左子树的深度大于右子树的深度):若BBST的左子树根结点的平衡因子为1, 则需进行单向右旋平衡处理,并且在右旋处理之后,将根结点和其右子树根结点的平衡因子更改为 0, 树的深度不变; ? 若BBST的左子树根结点的平衡因子为-1,则需进行先向左、后向右的双向旋转平衡处理,,并且在旋转处理之后。修改根结点和其左、右子树根结点的平衡因子,树的深度不变。 ② 若e的关键字大于BBST的根结点的关键字,而且在BBST的右子树中不存在和e有相同关键字的结点,则将e插入在BBST的右子树上,并且当插入之后的右子树深度增加(+I)时,分别就不同情况处理之。其处理操作和③ 中所述相对称,可自行补充。
|