查找(动态查找表——二叉查找和二叉平衡树)

一:
一、二叉排序树
(二叉查找树)
 
1.定义:
二叉排序树 或者是一棵空树;或者
是具有如下特性的二叉树:
1 )若它的左子树不空,则左子树上
          所有 结点的值 均小于 根结点的值;
2 )若它的右子树不空,则右子树上
          所有结点的值均大于根结点的值
3 )它的左、右子树 也都 分别 是二叉
          排序树
2.查找算法:
在二叉排序树上进行查找, 是一个从根结点开 始,沿某一个分支逐层向下进行比较判等的过程。 它可以是一个递归的过程。
若二叉排序树 为空 则查找不成功;否则
1)若给定值 等于 根结点的关键字,则查找成功;
2)若给定值 小于 根结点的关键字,则继续在左子树上进行查找;
3)若给定值 大于 根结点的关键字,则继续在右子树上进行查找
从根结点出发,沿着左分支或右分支逐层向 下直至关键字等于给定值的结点 ;
                       
—— 查找成功
从根结点出发,沿着左分支或右分支逐层向 下直至指针指向空树为止。
—— 查找不成功
3.二叉排序树的插入算法
根据动态查找表的定义,“插入”操作在查找不成功时才进行;
 
若二叉排序树为空树,则新插入的结点为新的根结点;否则,新插入的结点必为一个 新的叶 子结点 ,其插入位置由查找过程得到。
 
为了向二叉排序树中插入一个新元素,必须先检查这个元素是否在树中已经存在,即:在插入之前,先使用查找算法在树中检查要插入元素有还是没有。
搜索成功 : 树中已有这个元素,不再插入。
 搜索不成功 : 树中原来没有关键字等于给
定值的结点,把新元素加到查找操作停止的地方。
 
3. 二叉排序树 - 插入算法
BstTree BstInsert ( BstTree &t, ElemType x )
{
  // 查找 x
  p = t;   f = NULL; // f 指向p的双亲
  while ( p ) {
    if ( p->data==x )   return p; //查找成功
      else   if ( x<p->data ) { f = p; p = p->lchild; }
                     else { f = p;    p = p->rchild; }
    }
  }
  // 未找到,插入 x  

3. 二叉排序树 - 插入算法
// 未找到,插入 x
  s = malloc(sizeof(BiNode));
  s->data = x;
  s->lchild = s->rchild = NULL;
  if ( f == NULL )  
           t = s;    // 插入s为根结点
     else   if ( x < f->data )    f->lchild = s;
                 else     f->rchild = s;
  return s;  // 返回插入结点
}

4.二叉排序树的删除算法
和插入相反,删除在 查找成功 之后进行,并且要 求在删除二叉排序树上某个结点之后, 仍然保持 二叉排序树的特性
在二叉排序树中删除一个结点时,必须将因删除结点而断开的二叉链表重新链接起来,同时确保二叉排序树的性质不会失去。
为保证在执行删除后,树的搜索性能不至于降低,还需要防止重新链接后树的高度增加
 
可分 三种情况 讨论:
(1)被删除的结点 是叶子
(2)被删除的结点 只有左子树 或者 只有 右子树
(3)被删除的结点 既有左子树,也有右 子树
 
4. 二叉排序树 - 删除算法
BstTree BstDelete ( BstTree &t,   ElemType x )
{
  // 查找 x
  p = t;  f = NULL;  // f 指向p的双亲
  while ( p ) {
    if ( p->data==x ) break; //查找成功,进行删除
    else if ( x<p->data ) { f = p; p = p->lchild; }
    else { f = p; p = p->rchild; }
    }
  }
  // 若找到,删除结点
  if ( p != NULL ) …
  

                                      
                                      
2. 二叉排序树 - 删除算法
// 若找到,删除结点
  if ( p != NULL ) {
    // a) p 是叶子
    if ( p->lchild==NULL && p->rchild==NULL ) {
      if ( f==NULL ) t = NULL;
      else {
        if ( f->lchild==p ) f->lchild = NULL;
        else f->rchild = NULL;
      }
    }  
// b) p 只有一个子树
    else if ( p->lchild==NULL ) {  // p只有右子树
      if ( f==NULL ) t = p->rchild;
      else {
        if ( f->lchild==p ) f->lchild = p->rchild;
        else f->rchild = p->rchild;
      }
    }  
    else if ( p->rchild==NULL ) { // p只有左子树
      if ( f==NULL ) t = p->lchild;
      else {
        if ( f->lchild==p ) f->lchild = p->lchild;
        else f->rchild = p->lchild;
      }
    }  
// b) p 既有左子树也有右子树
    else {
      //找到p的“前驱”(左子树上的最大元素)
      q = p; s = p->lchild;
      while ( s->rchild ) { q = s; s = s->rchild; }
      //用p的“前驱”s代替p
      p->data = s->data;
      //删除s(s的右子树必然为空)
      if ( q != p ) q->rchild = s->lchild;
      else q->lchild = s->lchild;
    }
 } // if (p!=NULL)
  // 返回被删除结点,若未找到时返回NULL
  return p;
}


5.查找性能的分析
对于每一棵特定的二叉排序树,均可按 照平均查找长度的定义来求它的 ASL 值,显然,由值相同的 n 个关键字,构 造所得的不同形态的各棵二叉排序树的 平均查找长 度的值不同,甚至可能差 别很大。
 
四: 二叉平衡树
AVL 树的定义
一棵AVL树或者是空树,或者是具有下列性质的二叉搜索树: 它的左子树和右子树都是 AVL 树,且左 子树和右子树的高度之差的绝对值不超过 1
二叉平衡树的 特点为:
 
树中每个结点的 左、右子树深度之差的 绝对值不大于 1                  
结点的平衡因子 balance (balance factor)
每个结点附加一个数字,给出该结点左子树的高度减去右子树的高度所得的高度差。这个数字即为结点的 平衡因子balance 根据 AVL 树的定义,任一结点的平 衡因子只能取 -1 0 1
      如果一个结点的平衡因子的绝对值大于1,则这棵二叉搜索树就失去了平衡,不再是AVL树。
如果一棵二叉搜索树是高度平衡的,它就成为 AVL 。如果它有 n 个结点,其高度可保持在O(log 2 n ),平 均搜索长度也可保持在O(log 2 n )。
平衡化旋转
如果在一棵平衡的二叉搜索树中插入一个新结点,造成了不平衡。此时必须调整树的结构,使之平衡化。
平衡化旋转有两类:
  单旋转 (左旋和右旋)
 双旋转 (左平衡和右平衡)
每插入一个新结点时,AVL树中相关结点的平衡状态会发生改变。因此,在插入一个新结点后,需要 从插入 位置沿通向根的路径回溯 检查各结点的平衡 因子(左、右子树的高度差) 如果在某一结点 发现高度不平衡,停止回溯。
 
从发生不平衡的结点起,沿刚才回溯的路径取直接下两层的结点。
如果这三个结点处于一条直线上,则采用单旋转进行 平衡化 。单旋转可按其方向分为左单旋转和右单旋转,其中一个是另一个的镜像,其方向与不平衡的形状相关。
如果这三个结点处于一条折线上,则采用双旋转进行 平衡化 。双旋转分为先左后右和先右后左两类。
 
例,输入关键码序列为 { 16, 3, 7, 11, 9, 26, 18, 14, 15 } 插入和调整过程如下。
 
 
 
平衡树的查找性能分析:
 
在平衡树上进行查找的过程和二叉排序树相 同,因此, 查找过程中和给定值进行比较的 关键字的个数不超过平衡 树的深度。
 
问:含 n 个关键字 的二叉平衡树 可能达 到的最大深度 是多少?
 
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值