9.2
动 态 查 找 表
一、二叉排序树(二叉查找树)

二、二叉平衡树

三、 B - 树

四、 B+ 树
一、二叉排序树
(二叉查找树)
1 .定义
  2 .查找算法
    3 .插入算法
        4 .删除算法
         5 .查找性能的分析
1 .定义:
  二叉排序树 (Binary Sort Tree) 或者是
一棵空树;或者是具有如下特性的二叉树:
( 1 )若它的左子树不空,则左子树上
      所有结点的值均小于根结点的值;
( 2 )若它的右子树不空,则右子树上
      所有结点的值均大于根结点的值;
( 3 )它的左、右子树也都分别是二叉
      排序树。
例如 :                     50
               30                  80
     20                  40                  90

10        25        35        66        85
     23                                      88

          不是二叉排序树。
通常,取二叉链表作为
     二叉排序树的存储结构

typedef struct BiTNode { // 结点结构
  TElemType data;
   struct BiTNode *lchild, *rchild;
                     // 左右孩子指针
} BiTNode, *BiTree;
2 .二叉排序树的查找算法:
若二叉排序树为空,则查找不成功;
否则,
1 )若给定值等于根结点的关键字,
  则查找成功;
2 )若给定值小于根结点的关键字,
  则继续在左子树上进行查找;
3 )若给定值大于根结点的关键字,
  则继续在右子树上进行查找。
例如 : 二叉排序树
                 50
          30               80
   20           40               90
                                        NULL
           35               85
     32                            88

查找关键字
  == 50 , 35 , 90 , 95 ,
从上述查找过程可见,
在查找过程中,生成了一条查找路径:
 从根结点出发,沿着左分支或右分
支逐层向下直至关键字等于给定值的
结点 ;     — — 查找成
     或者
         功
 从根结点出发,沿着左分支或右分
支逐层向下直至指针指向空树为止。
         — — 查找不成
算法描述如下:
 Status SearchBST (BiTree T, KeyType key,
                   BiTree f, BiTree &p ) {
   // 在根指针 T 所指二叉排序树中递归地查找其
  // 关键字等于 key 的数据元素,若查找成功,
  // 则返回指针 p 指向该数据元素的结点,并返
  回                否则表明查找不成功,返
  // 函数值为 TRUE;
针 p 指向查找路径上访问的最后一个结点,
返回函数值为 FALSE, 指针 f 指向当前访问
结点的双亲,其初始调用值为 NULL
      …………
if (!T)
    { p = f; return FALSE; } // 查找不成功
else if ( EQ(key, T->data.key) )
   { p = T; return TRUE; } // 查找成功
else if ( LT(key, T->data.key) )
   SearchBST (T->lchild, key, T, p );
                  // 在左子树中继续查找
elseSearchBST (T->rchild, key, T, p );
                  // 在右子树中继续查找
f T           f
设 key = 22
        48                  f      Tf

         T        f                         f   Tp
                               30
                          T
             20                f            40       T


   10        Tp       f   25        35

     T            23
3 .二叉排序树的插入算
      法
• 根据动态查找表的定义,“ 插入 ”
  操作在查找不成功时才进行;
• 若二叉排序树为空树,则新插入的结点
  为新的根结点;否则,新插入的结点必
  为一个新的叶子结点,插入位置是查找
  不成功时查找路径上访问的最后一个结
  点的左孩子或右孩子结点 , 插入在查找
  过程中实现 .
Status Insert BST(BiTree &T, ElemType e )
{ // 当二叉排序树中不存在关键字等于 e.key 的
// 数据元素时,插入元素值为 e 的结点,并返
// 回 TRUE; 否则,不进行插入并返回 FALSE
  if (!SearchBST ( T, e.key, NULL, p ))
 {       … …        }
  else return FALSE;
} // Insert BST
s = (BiTree) malloc (sizeof (BiTNode));
                     // 为新结点分配空间
  s->data = e;
  s->lchild = s->rchild = NULL;
if ( !p ) T = s;      // 插入 s 为新的根结点

else if ( LT(e.key, p->data.key) )
    p->lchild = s;     // 插入 *s 为 *p 的左孩子
else p->rchild = s; // 插入 *s 为 *p 的右孩子
  return TRUE;        // 插入成功
4 .二叉排序树的删除算法
  和插入相反,删除在查找成功之
后进行,并且要求在删除二叉排序树
上某个结点之后,仍然保持二叉排序
树的特性。
4 .二叉排序树的删除算法
可分三种情况讨论:
 ( 1 )被删除的结点是叶子;
 ( 2 )被删除的结点只有左子树或
 者只有右子树;
 ( 3 )被删除的结点既有左子树,
 也有右子树。
( 1 )被删除的结点是叶子结点
 例如 :                被删关键字 =88
                             20
               50
        30          80
  20          40          90
         35          85
   32                       88

 其双亲结点中相应指针域的值改为 “ NULL”
( 2 )被删除的结点只有左子树
或者只有右子树          被删关键字 =80
                         40
           50
       30     80
    20    40      90
        35     85
   32               88
      其双亲结点的相应指针域的值改
 为 “ 指向被删除结点的左子树或右子树
( 3 )被删除的结点既有左子树,也有右子树
                       f
             p
                   50       被删关键字 = 30
      s     30             80
     20           40          90
             35            85
       32                       88

  令 *p 的左子树为 *f 的左子树 ,*p 的右子树为 *s 的
  右子树 .
( 3 )被删除的结点既有左子树,也有右子树

                       被删关键字 = 50
                 40
                 50
         30           80
   20           40          90
          35           85
    32                        88
  前驱结点         被删结点
                      以其前驱替代之,
                      然后再删除该前驱
算法描述如下:
Status DeleteBST (BiTree &T, KeyType key )
{
 // 若二叉排序树 T 中存在其关键字等于
key 的
 // 数据元素,则删除该数据元素结点,并
返回
 // 函数值 TRUE ,否则返回函数值
FALSE … …
 if (!T) return FALSE; //   不存在关键字等
if ( EQ (key, T->data.key) )
       { Delete (T); return TRUE; }
       // 找到关键字等于 key 的数据元素
else if ( LT (key, T->data.key) )
        DeleteBST ( T->lchild, key );
          // 继续在左子树中进行查找
else    DeleteBST ( T->rchild, key );
          // 继续在右子树中进行查找
其中删除操作过程如下所描述:

 void Delete ( BiTree &p ){
  // 从二叉排序树中删除结点 p ,
  // 并重接它的左子树或右子树
   if (!p->rchild) { … … }
   else if (!p->lchild) { … … }
   else { … … }
 } // Delete
// 右子树为空树则只需重接它的左子树
     q = p; p = p->lchild; free(q);
              f 是 p 的父亲
              结点

      q p                      p
                                q
 p
                               p
// 左子树为空树只需重接它的右子树
  q = p; p = p->rchild; free(q);
         f 是 p 的父亲
         结点

 q p                      pq

                                   p
   p
// 左右子树均不空
q = p; s = p->lchild;
while (s->rchild) { q = s; s = s->rchild; }
              // s 指向被删结点的前驱
p->data = s->data; // 前驱替换被删结点
if (q != p ) q->rchild = s->lchild;
                                    q p
else q->lchild = s->lchild;
             // 重接 *q 的左子树          s
free(s);
5 .查找性能的分析
   对于每一棵特定的二叉排序树
,均可按照平均查找长度的定义来求
它的 ASL 值,显然,由值相同的 n
个关键字,构造所得的不同形态的各
棵二叉排序树的平均查找长 度的值不
同,甚至可能差别很大。
例如:                         1

由关键字序列 1 , 2 , 3 ,                  2
                                            3
4 , 5 构造而得的二叉排序树                                 4
,ASL = ( 1+2+3+4+5 ) / 5                             5

     =3
                                             3
由关键字序列
                                1                    5
3 , 1 , 2 , 5 , 4 构造而得
的二叉排序树,
  ASL = ( 1+2+3+2+3 ) / 5               2        4

       = 2.2
下面讨论平均情况 :
    不失一般性,假设长度为 n 的序
 列中有 k 个关键字小于第一个关键字
 ,则必有 n-k-1 个关键字大于第一个关
 键字 , 由它构造的二叉排序树:
               k           n-k-1

的平均查找长度是 n 和 k 的函数
     P(n, k)       ( 0≤ k ≤ n-1 )
1
P(n, k) = [1 + k * (P(k) + 1) + (n − k − 1) * (P(n − k − 1) + 1)]
         n


  其中 P(k) 为含有 k 个结点的二叉排序树
的平均查找长度 . 则 P(k)+1 为查找左子树所
用比较次数的平均值 , 而 P(n-k-1) 为查找右子
树中每个结点所用比较次数的平均值 .
假设 n 个关键字的排列是随机的 , 即任一
个关键字在序列中将是第 1 个,或第 2
个 , . . . 的概率相同 , 则含 n 个关键字的二
叉排序树的平均查找长度:
                  n −1
                 1
     ASL = P(n) = ∑ P(n, k)
                 n k =0
在等概率查找的情况下,
       1 n −1  1                                        
 P(n) = ∑  1 + ( k × P(k) + (n − k − 1) × P(n − k − 1)) 
       n k =0  n                                        
               n −1
           2
      = 1+ 2
          n
               ∑ ( k × P(k))
               k =1


可类似于解差分方程,此递归方程有解:
                    n +1
         P ( n) = 2      log n + C
                      n
性能分析

        由此可见 , 在随机的情况下 , 二
叉排序树的平均查找长度和 log n 是等
数量级的 . 但这种情况出现的概率约为
46.5%, 尚需在构成二叉排序树的过程中
进行”平衡化”处理 , 成为二叉平衡树
(Balanced Binary Tree).
二、二叉平衡树
• 何谓 “ 二叉平衡树 ” ?
• 如何构造 “ 二叉平衡树 ”

• 二叉平衡树的查找性能分
  析
二叉平衡树是二叉查找树的另一种形
式,其特点为:

   树中每个结点的左、右子树深度之
差的绝对值不大于 − hR ≤ 1
       hL 1       。
例如 :       5                   5
                           4       8
       4       8
                       2
 2
     是平衡树          1       不是平衡树
结点的平衡因子
例如 :       5               1
       4       8       1       0
  2                0
                       是平衡树

结点的平衡因子 BF(Balance Factor) :
结点的左子树的深度减去 - 右子树的深度 .
因此 , 平衡二叉树上所有结点的平衡因子只可能
是
(-1,0,1). 只要二叉树上存在一个结点的 BF 的绝
对值
大于 1, 则该树就不是平衡的 .
构造二叉平衡(查找)树的方法是:
在插入过程中,采用平衡旋转技术。
     假设由于在二叉排序树上插入结
点而
失去平衡的最小子树根结点为 A ,沿插入
路径取直接下两层的结点为 B 和 C ,如果
这
三个结点处于一条直线上,则采用单旋转
进行平衡化;如果这三个结点处于一条折
线
( 1 )单向右旋平衡处理: ( LLR)
 原因:在 A 的左子树根结点的左子树上插入结点,
的平衡因子由 1 增至 2 ,至使以 A 为根的子树失去平衡
 调整方法:以结点 B 为旋转轴,将结点 A 向右旋转
成为
B 的右子树,结点 B 代替原来 A 的位置,原来 B 的右
子树                   B
            A
成为 A 的左子树。 R
         A                               A
        B              LL   C
                BR h            h+1 BR       AR
    C                  R
        h       h                    h       h

    插入结点
( 2 )单向左旋平衡处理: ( RRL)
 原因:在 A 的右子树根结点的右子树上插入结点,
的平衡因子由 - 1 增至 - 2 ,至使以 A 为根的子树失去平
 调整方法:以结点 B 为旋转轴,将结点 A 向左旋转
成为
B 的左子树,结点 B 代替原来 A 的位置,原来 B 的左
子树                    B
      A
成为 A A
     的右子树。
         B                      A       C
      L               RR
          BL    C          AL       BL h+1
     h
                      L
          h     h           h       h

               插入结点
( 3 )先左后右平衡处理: ( LRLR)
  原因:在 A 的左子树根结点的右子树上插入结点,
的平衡因子由 1 增至 2 ,至使以 A 为根的子树失去平衡
    调整方法:先以 C 为旋转轴,将结点 B 向左旋转
 成为
 C 的左子树,结点 C 代替原来 B 的位置,原来 C 的左
 子树      再以 C 为旋转轴,将 A 向右旋转成为
 成为 B 的右子树。 C 代替原来 A 的位置,原来 C 的右
 C 的右子树,结点
 子树
 成为 B 的左子树。
      A          A        C
                                C          AR
                AR                                   B       A
        B
                h           B         CR h
   BL                 L                         R
            C                        h-1            BL   CL CR AR
        h              BL
                 CR             CL                   h   h h-1 h
    CL                      h   h
       h-1      h-1
 插入结点
( 4 )先右后左平衡处理: ( RLRL)
 原因:在 A 的右子树根结点的左子树上插入结点,
的平衡因子由 - 1 增至 - 2 ,至使以 A 为根的子树失去平
    调整方法:先以 C 为旋转轴,将结点 B 向右旋转
 成为
 C 的右子树,结点 C 代替原来 B 的位置,原来 C 的右
 子树      再以 C 为旋转轴,将 A 向左旋转成为
 成为 B 的左子树。 C 代替原来 A 的位置,原来 C 的左
 C 的左子树,结点
 子树
 成为 A 的右子树。
     B           A          C
                         AL           C
  AL       B                                      A       B
                          h C
   h                         L            B L
       C        BR   R
                              h-1               AL CL      CR BR
               h
                                 CR        BR    h    h-1 h h
  CL
    h-1 h-1 CR                    h       h
   插入结点
例如 : 依次插入的关键字为 5, 4, 2, 8, 6, 9


              A 5        B
                             4             4
      B              C           A                  C
          4          2           5 A   2        6
 C                                                      B
  2                              B 8       5A           8
                    向右旋转         6C    先向右旋转
                     一次                再向左旋转
向左旋转一次
         A
     4
                 B
 2           6
                         C
     5               8
                                         B
                             9           6
                                     A       C
                                     4       8
继续插入关键字                          2       5       9
9
平衡树的查找性能分析:
   在平衡树上进行查找的过程和二
叉排序树相同,因此,查找过程中和给
定值进行比较的关键字的个数不超过平
衡 树的深度。

 问:含 n 个关键字的二叉平衡
树可能达到的最大深度是多少?
先看几个具体情况 :
  n=0        n=1       n=2

  空树

最大深度为    最大深度为     最大深度为
0        1         2
n=4          n=7



 最大深度为             最大深度为
反过来问,深度为 h 的二叉平衡树
中所含结点的最小值 Nh 是多少?
h=0   N0 = 0        h=1       N1 = 1

h=2   N2 = 2        h=3       N3 = 4

一般情况下          Nh = Nh-1 + Nh-2 + 1

利用归纳法可证得              Nh = Fh+2 - 1
一般情况下        Nh = Nh-1 + Nh-2 + 1

利用归纳法可证得            Nh = Fh+2 - 1

Fh 为斐波那契序列 ( 书 P221) 且

                     1+ 5
   Fh = ϕ / 5 (其中ϕ =
       h
                          )
                       2
由此推得,深度为 h 的二叉平衡
树中所含结点的最小值 Nh = ϕ h+2/ √ 5 -
1。反之,含有 n 个结点的二叉平衡
树能达到的最大深度 hn = logϕ (√5
(n+1)) - 2 。
   因此,在二叉平衡树上进行查找时
,
查找过程中和给定值进行比较的关键
字的个数和 log(n) 相当。

第九章 查找[2]

  • 1.
  • 2.
  • 3.
    一、二叉排序树 (二叉查找树) 1 .定义 2 .查找算法 3 .插入算法 4 .删除算法 5 .查找性能的分析
  • 4.
    1 .定义: 二叉排序树 (Binary Sort Tree) 或者是 一棵空树;或者是具有如下特性的二叉树: ( 1 )若它的左子树不空,则左子树上 所有结点的值均小于根结点的值; ( 2 )若它的右子树不空,则右子树上 所有结点的值均大于根结点的值; ( 3 )它的左、右子树也都分别是二叉 排序树。
  • 5.
    例如 : 50 30 80 20 40 90 10 25 35 66 85 23 88 不是二叉排序树。
  • 6.
    通常,取二叉链表作为 二叉排序树的存储结构 typedef struct BiTNode { // 结点结构 TElemType data; struct BiTNode *lchild, *rchild; // 左右孩子指针 } BiTNode, *BiTree;
  • 7.
    2 .二叉排序树的查找算法: 若二叉排序树为空,则查找不成功; 否则, 1 )若给定值等于根结点的关键字, 则查找成功; 2 )若给定值小于根结点的关键字, 则继续在左子树上进行查找; 3 )若给定值大于根结点的关键字, 则继续在右子树上进行查找。
  • 8.
    例如 : 二叉排序树 50 30 80 20 40 90 NULL 35 85 32 88 查找关键字 == 50 , 35 , 90 , 95 ,
  • 9.
    从上述查找过程可见, 在查找过程中,生成了一条查找路径: 从根结点出发,沿着左分支或右分 支逐层向下直至关键字等于给定值的 结点 ; — — 查找成 或者 功 从根结点出发,沿着左分支或右分 支逐层向下直至指针指向空树为止。 — — 查找不成
  • 10.
    算法描述如下: Status SearchBST(BiTree T, KeyType key, BiTree f, BiTree &p ) { // 在根指针 T 所指二叉排序树中递归地查找其 // 关键字等于 key 的数据元素,若查找成功, // 则返回指针 p 指向该数据元素的结点,并返 回 否则表明查找不成功,返 // 函数值为 TRUE; 针 p 指向查找路径上访问的最后一个结点, 返回函数值为 FALSE, 指针 f 指向当前访问 结点的双亲,其初始调用值为 NULL …………
  • 11.
    if (!T) { p = f; return FALSE; } // 查找不成功 else if ( EQ(key, T->data.key) ) { p = T; return TRUE; } // 查找成功 else if ( LT(key, T->data.key) ) SearchBST (T->lchild, key, T, p ); // 在左子树中继续查找 elseSearchBST (T->rchild, key, T, p ); // 在右子树中继续查找
  • 12.
    f T f 设 key = 22 48 f Tf T f f Tp 30 T 20 f 40 T 10 Tp f 25 35 T 23
  • 13.
    3 .二叉排序树的插入算 法 • 根据动态查找表的定义,“ 插入 ” 操作在查找不成功时才进行; • 若二叉排序树为空树,则新插入的结点 为新的根结点;否则,新插入的结点必 为一个新的叶子结点,插入位置是查找 不成功时查找路径上访问的最后一个结 点的左孩子或右孩子结点 , 插入在查找 过程中实现 .
  • 14.
    Status Insert BST(BiTree&T, ElemType e ) { // 当二叉排序树中不存在关键字等于 e.key 的 // 数据元素时,插入元素值为 e 的结点,并返 // 回 TRUE; 否则,不进行插入并返回 FALSE if (!SearchBST ( T, e.key, NULL, p )) { … … } else return FALSE; } // Insert BST
  • 15.
    s = (BiTree)malloc (sizeof (BiTNode)); // 为新结点分配空间 s->data = e; s->lchild = s->rchild = NULL; if ( !p ) T = s; // 插入 s 为新的根结点 else if ( LT(e.key, p->data.key) ) p->lchild = s; // 插入 *s 为 *p 的左孩子 else p->rchild = s; // 插入 *s 为 *p 的右孩子 return TRUE; // 插入成功
  • 16.
    4 .二叉排序树的删除算法 和插入相反,删除在查找成功之 后进行,并且要求在删除二叉排序树 上某个结点之后,仍然保持二叉排序 树的特性。
  • 17.
    4 .二叉排序树的删除算法 可分三种情况讨论: (1 )被删除的结点是叶子; ( 2 )被删除的结点只有左子树或 者只有右子树; ( 3 )被删除的结点既有左子树, 也有右子树。
  • 18.
    ( 1 )被删除的结点是叶子结点 例如 : 被删关键字 =88 20 50 30 80 20 40 90 35 85 32 88 其双亲结点中相应指针域的值改为 “ NULL”
  • 19.
    ( 2 )被删除的结点只有左子树 或者只有右子树 被删关键字 =80 40 50 30 80 20 40 90 35 85 32 88 其双亲结点的相应指针域的值改 为 “ 指向被删除结点的左子树或右子树
  • 20.
    ( 3 )被删除的结点既有左子树,也有右子树 f p 50 被删关键字 = 30 s 30 80 20 40 90 35 85 32 88 令 *p 的左子树为 *f 的左子树 ,*p 的右子树为 *s 的 右子树 .
  • 21.
    ( 3 )被删除的结点既有左子树,也有右子树 被删关键字 = 50 40 50 30 80 20 40 90 35 85 32 88 前驱结点 被删结点 以其前驱替代之, 然后再删除该前驱
  • 22.
    算法描述如下: Status DeleteBST (BiTree&T, KeyType key ) { // 若二叉排序树 T 中存在其关键字等于 key 的 // 数据元素,则删除该数据元素结点,并 返回 // 函数值 TRUE ,否则返回函数值 FALSE … … if (!T) return FALSE; // 不存在关键字等
  • 23.
    if ( EQ(key, T->data.key) ) { Delete (T); return TRUE; } // 找到关键字等于 key 的数据元素 else if ( LT (key, T->data.key) ) DeleteBST ( T->lchild, key ); // 继续在左子树中进行查找 else DeleteBST ( T->rchild, key ); // 继续在右子树中进行查找
  • 24.
    其中删除操作过程如下所描述: void Delete( BiTree &p ){ // 从二叉排序树中删除结点 p , // 并重接它的左子树或右子树 if (!p->rchild) { … … } else if (!p->lchild) { … … } else { … … } } // Delete
  • 25.
    // 右子树为空树则只需重接它的左子树 q = p; p = p->lchild; free(q); f 是 p 的父亲 结点 q p p q p p
  • 26.
    // 左子树为空树只需重接它的右子树 q = p; p = p->rchild; free(q); f 是 p 的父亲 结点 q p pq p p
  • 27.
    // 左右子树均不空 q =p; s = p->lchild; while (s->rchild) { q = s; s = s->rchild; } // s 指向被删结点的前驱 p->data = s->data; // 前驱替换被删结点 if (q != p ) q->rchild = s->lchild; q p else q->lchild = s->lchild; // 重接 *q 的左子树 s free(s);
  • 28.
    5 .查找性能的分析 对于每一棵特定的二叉排序树 ,均可按照平均查找长度的定义来求 它的 ASL 值,显然,由值相同的 n 个关键字,构造所得的不同形态的各 棵二叉排序树的平均查找长 度的值不 同,甚至可能差别很大。
  • 29.
    例如: 1 由关键字序列 1 , 2 , 3 , 2 3 4 , 5 构造而得的二叉排序树 4 ,ASL = ( 1+2+3+4+5 ) / 5 5 =3 3 由关键字序列 1 5 3 , 1 , 2 , 5 , 4 构造而得 的二叉排序树, ASL = ( 1+2+3+2+3 ) / 5 2 4 = 2.2
  • 30.
    下面讨论平均情况 : 不失一般性,假设长度为 n 的序 列中有 k 个关键字小于第一个关键字 ,则必有 n-k-1 个关键字大于第一个关 键字 , 由它构造的二叉排序树: k n-k-1 的平均查找长度是 n 和 k 的函数 P(n, k) ( 0≤ k ≤ n-1 )
  • 31.
    1 P(n, k) =[1 + k * (P(k) + 1) + (n − k − 1) * (P(n − k − 1) + 1)] n 其中 P(k) 为含有 k 个结点的二叉排序树 的平均查找长度 . 则 P(k)+1 为查找左子树所 用比较次数的平均值 , 而 P(n-k-1) 为查找右子 树中每个结点所用比较次数的平均值 .
  • 32.
    假设 n 个关键字的排列是随机的, 即任一 个关键字在序列中将是第 1 个,或第 2 个 , . . . 的概率相同 , 则含 n 个关键字的二 叉排序树的平均查找长度: n −1 1 ASL = P(n) = ∑ P(n, k) n k =0
  • 33.
    在等概率查找的情况下, 1 n −1  1  P(n) = ∑  1 + ( k × P(k) + (n − k − 1) × P(n − k − 1))  n k =0  n  n −1 2 = 1+ 2 n ∑ ( k × P(k)) k =1 可类似于解差分方程,此递归方程有解: n +1 P ( n) = 2 log n + C n
  • 34.
    性能分析 由此可见 , 在随机的情况下 , 二 叉排序树的平均查找长度和 log n 是等 数量级的 . 但这种情况出现的概率约为 46.5%, 尚需在构成二叉排序树的过程中 进行”平衡化”处理 , 成为二叉平衡树 (Balanced Binary Tree).
  • 35.
    二、二叉平衡树 • 何谓 “二叉平衡树 ” ? • 如何构造 “ 二叉平衡树 ” • 二叉平衡树的查找性能分 析
  • 36.
    二叉平衡树是二叉查找树的另一种形 式,其特点为: 树中每个结点的左、右子树深度之 差的绝对值不大于 − hR ≤ 1 hL 1 。 例如 : 5 5 4 8 4 8 2 2 是平衡树 1 不是平衡树
  • 37.
    结点的平衡因子 例如 : 5 1 4 8 1 0 2 0 是平衡树 结点的平衡因子 BF(Balance Factor) : 结点的左子树的深度减去 - 右子树的深度 . 因此 , 平衡二叉树上所有结点的平衡因子只可能 是 (-1,0,1). 只要二叉树上存在一个结点的 BF 的绝 对值 大于 1, 则该树就不是平衡的 .
  • 38.
    构造二叉平衡(查找)树的方法是: 在插入过程中,采用平衡旋转技术。 假设由于在二叉排序树上插入结 点而 失去平衡的最小子树根结点为 A ,沿插入 路径取直接下两层的结点为 B 和 C ,如果 这 三个结点处于一条直线上,则采用单旋转 进行平衡化;如果这三个结点处于一条折 线
  • 39.
    ( 1 )单向右旋平衡处理:( LLR) 原因:在 A 的左子树根结点的左子树上插入结点, 的平衡因子由 1 增至 2 ,至使以 A 为根的子树失去平衡 调整方法:以结点 B 为旋转轴,将结点 A 向右旋转 成为 B 的右子树,结点 B 代替原来 A 的位置,原来 B 的右 子树 B A 成为 A 的左子树。 R A A B LL C BR h h+1 BR AR C R h h h h 插入结点
  • 40.
    ( 2 )单向左旋平衡处理:( RRL) 原因:在 A 的右子树根结点的右子树上插入结点, 的平衡因子由 - 1 增至 - 2 ,至使以 A 为根的子树失去平 调整方法:以结点 B 为旋转轴,将结点 A 向左旋转 成为 B 的左子树,结点 B 代替原来 A 的位置,原来 B 的左 子树 B A 成为 A A 的右子树。 B A C L RR BL C AL BL h+1 h L h h h h 插入结点
  • 41.
    ( 3 )先左后右平衡处理:( LRLR) 原因:在 A 的左子树根结点的右子树上插入结点, 的平衡因子由 1 增至 2 ,至使以 A 为根的子树失去平衡 调整方法:先以 C 为旋转轴,将结点 B 向左旋转 成为 C 的左子树,结点 C 代替原来 B 的位置,原来 C 的左 子树 再以 C 为旋转轴,将 A 向右旋转成为 成为 B 的右子树。 C 代替原来 A 的位置,原来 C 的右 C 的右子树,结点 子树 成为 B 的左子树。 A A C C AR AR B A B h B CR h BL L R C h-1 BL CL CR AR h BL CR CL h h h-1 h CL h h h-1 h-1 插入结点
  • 42.
    ( 4 )先右后左平衡处理:( RLRL) 原因:在 A 的右子树根结点的左子树上插入结点, 的平衡因子由 - 1 增至 - 2 ,至使以 A 为根的子树失去平 调整方法:先以 C 为旋转轴,将结点 B 向右旋转 成为 C 的右子树,结点 C 代替原来 B 的位置,原来 C 的右 子树 再以 C 为旋转轴,将 A 向左旋转成为 成为 B 的左子树。 C 代替原来 A 的位置,原来 C 的左 C 的左子树,结点 子树 成为 A 的右子树。 B A C AL C AL B A B h C h L B L C BR R h-1 AL CL CR BR h CR BR h h-1 h h CL h-1 h-1 CR h h 插入结点
  • 43.
    例如 : 依次插入的关键字为5, 4, 2, 8, 6, 9 A 5 B 4 4 B C A C 4 2 5 A 2 6 C B 2 B 8 5A 8 向右旋转 6C 先向右旋转 一次 再向左旋转
  • 44.
    向左旋转一次 A 4 B 2 6 C 5 8 B 9 6 A C 4 8 继续插入关键字 2 5 9 9
  • 45.
    平衡树的查找性能分析: 在平衡树上进行查找的过程和二 叉排序树相同,因此,查找过程中和给 定值进行比较的关键字的个数不超过平 衡 树的深度。 问:含 n 个关键字的二叉平衡 树可能达到的最大深度是多少?
  • 46.
    先看几个具体情况 : n=0 n=1 n=2 空树 最大深度为 最大深度为 最大深度为 0 1 2 n=4 n=7 最大深度为 最大深度为
  • 47.
    反过来问,深度为 h 的二叉平衡树 中所含结点的最小值Nh 是多少? h=0 N0 = 0 h=1 N1 = 1 h=2 N2 = 2 h=3 N3 = 4 一般情况下 Nh = Nh-1 + Nh-2 + 1 利用归纳法可证得 Nh = Fh+2 - 1
  • 48.
    一般情况下 Nh = Nh-1 + Nh-2 + 1 利用归纳法可证得 Nh = Fh+2 - 1 Fh 为斐波那契序列 ( 书 P221) 且 1+ 5 Fh = ϕ / 5 (其中ϕ = h ) 2
  • 49.
    由此推得,深度为 h 的二叉平衡 树中所含结点的最小值Nh = ϕ h+2/ √ 5 - 1。反之,含有 n 个结点的二叉平衡 树能达到的最大深度 hn = logϕ (√5 (n+1)) - 2 。 因此,在二叉平衡树上进行查找时 , 查找过程中和给定值进行比较的关键 字的个数和 log(n) 相当。