码迷,mamicode.com
首页 > 其他好文 > 详细

动态查找表

时间:2015-03-16 06:11:42      阅读:119      评论:0      收藏:0      [点我收藏+]

标签:

1.动态查找表的特点:表结构本身是在查找过程中动态生成的,即对于给定值key,若表中存在其关键字等于key的记录,则查找成功返回,否则插入关键字等于key的记录。

 1 //---------------抽象数据类型动态查找表的定义---------------------
 2 ADT DynamicSearchTable{
 3     数据对象D:D是具有相同特性的数据元素的集合。各个数据元素均含有类型相同,可惟一标识数据元素的关键字。
 4     数据关系R:数据元素同属一个集合。
 5     基本操作P:
 6         InitDSTable(&DT);
 7             操作结果:构造一个空的动态查找表DT。
 8         DestroyDSTable(&DT);
 9             初始条件:动态查找表存在。
10             操作结果:销毁动态查找表DT。
11         SearchDSTable(DT,key);
12             初始条件:动态查找表DT存在,key为和关键字类型相同的给定值。
13             操作结果:若DT中存在其关键字等于key的数据元素,则函数值为该元素的值或在表中的位置,否则为“空”。
14         InsertDSTable(&DT,e);
15             初始条件:动态查找表DT存在,e为待插入的数据元素。
16             操作结果:若DT中不存在其关键字等于e.key的数据元素,则插入e到DT。
17         DeleteDSTable(&DT,key);
18             初始条件:动态查找表DT存在,key为和关键字类型相同的给定值。
19             操作结果:若DT中存在其关键字等于key的数据元素,则删除之。
20         TraverseDSTable(DT,visit());
21             初始条件:动态查找表DT存在,Visit是对结点操作的应用函数。
22             操作结果:按某种次序对DT的每个结点调用函数Visit()一次且至多一次。一旦Visit()失败,操作失败。
23 }ADT DynamicSearchTable

2.二叉排序树及其查找过程

  二叉排序树(Binary Sort Tree)  或者是一棵空树;或者是具有下列性质的二叉树:

  (1)若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;

  (2)若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;

  (3)它的左、右子树也分别为二叉排序树。

3.二叉排序树查找过程

  当二叉排序树不空时,首先将给定值和根结点的关键字比较,若相等,则查找成功,否则将依据给定值和根结点的关键字之间的大小关系,分别在左子树或右子树上继续查找。通常,可取二叉链表作为二叉排序树的存储结构。

 1 //---------------------二叉排序树查找算法----------------------
 2 BiTree SearchBST(BiTree T,KeyType key){
 3     //在根指针T所指二叉排序树中递归地查找某关键字等于key的数据元素,若查找成功,则返回指向该数据元素结点的指针,否则返回空指针
 4     if((!T)||EQ(key,T->data.key))
 5         return(T);        //查找结束
 6     else if LT(key,T->data.key)
 7         return(SearchBST(T->lchild,key));        //在左子树中继续查找
 8     else 
 9         return(SearchBST(T->rchild,key));        //在右子树中继续查找
10 }//SearchBST

4.二叉排序树的删除

 1 //------------------------二叉排序树的查找算法---------------------
 2 Status  SearchBST(BiTree T,KeyType key,BiTree f,BiTree &p){
 3     //在根指针T所指二叉排序树中递归地查找其关键字等于key的数据元素,若查找成功,则指针p指向该数据元素结点,并返回TRUE,否则指针p指向查找路径上访问的最后一个结点并返回FALSE,指针f指向T的双亲,其初始掉用值为NULL
 4     if(!T)
 5         {p = f;return FALSE;}                //查找不成功
 6     else  if EQ(key,T->data.key)
 7         {p=T;return TRUE;}                //查找成功
 8     else if LT(key,T->data.key)
 9         return SearchBST(T->lchild,key,T,p);        //在左子树中继续查找
10     else
11         return SearchBST(T->rchild,key,T,p);        //在右子树中继续查找
12 }//SearchBST

 

 1 //--------------------------二叉排序树插入算法------------------
 2 Status InsertBST(BiTree &T,ElemType e){
 3     //当二叉排序树T中不存在关键字等于e.key的数据元素时,插入e并返回TRUE,否则返回FALSE。
 4     if(!SearchBST (T,e.key,NULL,p){                  //查找不成功
 5         s = (BiTree) malloc (sizeof (BiTNode));
 6         s->data = e;
 7         s->lchild = s->rchild = NULL;
 8         if (!p)
 9             T = s;                                     //被插结点*s为新的根结点
10         else if LT(e.key,p->data.key)
11             p->lchild = s;                            //被插结点*s为左孩子
12         else 
13             p->rchild = s;                            //被插结点*s为右孩子
14         return TRUE;
15         }
16         else return FALSE;                            //树中已有关键字相同的结点,不再插入
17 }//InsertBST

5.二叉排序树的删除

  假设在二叉排序树上被删结点为*p(指向结点的指针为p),其双亲结点为*f(结点指针为f),且不失一般性,可设*p是*f的左孩子。

  下面分3种情况进行讨论:

  (1)若*p结点为叶子结点,即P(L)和P(R)均为空树。由于删去叶子结点不破坏整棵树的结构,则只需修改器双亲结点的指针即可。

  (2)若*p结点只有左子树P(L)或者只有右子树P(R),此时只要令P(L)或P(R)直接成为其双亲结点*f的左子树即可。显然,作此修改也不破坏二叉排序树的特性。

  (3)若*p结点的左子树和右子树均不空。

 1 //-----------------------在二叉排序树上删除一个结点的算法---------------
 2 Status DeleteBST(BiTree &T,KeyType key){
 3     //若二叉排序树T中存在关键字等于key的数据元素时,则删除该数据元素结点,并返回TRUE;否则返回FALSE
 4     if(!T)
 5         return FALSE;                    //不存在关键字等于key的数据元素
 6     else {
 7         if (EQ(key,T->data.key))
 8             return Delete(T);            //找不到关键字等于key的数据元素
 9         else if (LT(key,T->data.key))
10             return DeleteBST(T->lchild,key);
11         else
12             return DeleteBST(T->rchild,key);
13         }
14 }//DeleteBST
//------------二叉排序树删除操作过程算法----------------
Status Delete (BiTree &p){
    //从二叉排序树中删除结点p,并重接它的左或右子树
    if (!p->rchild){        //右子树空则需重接它的左子树
        q = p; p = p->lchild; free(q);
    }
    else if (!p->lchild){    //只需重接它的右子树
        q = p; p = p->rchild; free(q);
    }
    else {        //左右子树均不空
        q = p; s = p->lchild;
        while(s->rchild)
            { q = s; s = s->rchild }        //转左,然后向右到尽头
        p->data = s->data;                    //s指向被删结点的“前驱"
        if(q!=p)
            q->rchild = s->lchild;            //重接*q的右子树
        else
            q->lchild = s->lchild;            //重接*q的左子树
        delete s;
        }
        return TRUE;
}//Delete

6.平衡二叉树

  平衡二叉树(Balanced Binary Tree或Height-Balanced Tree)又称AVL树。

  它或者是一棵空树,或者是具有下列性质的二叉树:

  它的左子树和右子树都是平衡二叉树,且左子树和右子树的深度之差的绝对值不超过1.

  若将二叉树上结点的平衡因子BF(Balanced Factor)定义为该结点的左子树的深度减去它的右子树的深度,则平衡二叉树上所有结点的平衡因子只可能是-1、0和1.

  只要二叉树上有一个结点的平衡因子的绝对值大于1,则该二叉树就是不平衡的。

7.在平衡二叉排序树BBST上插入一个新的数据元素e的递归算法可描述如下:

(1)若BBST为空树,则插入一个数据元素为e的新结点作为BBST的根结点,树的深度增1;

(2)若e的关键字和BBST的根结点的关键字相等,则不进行插入;

(3)若e的关键字小于BBST的根结点的关键字,而且在BBST的左子树中不存在和e有相同关键字的结点,则将e插入在BBST的左子树上,并且当插入之后的左子树深度增加(+1)时,分别就下列不同情况处理之:

  • BBST的根结点的平衡因子为-1(右子树的深度大于左子树的深度):则将根结点的平衡因子更改为0;BBST的深度不变;
  • BBST的根结点的平衡因子为0(左、右子树的深度相等):将根结点的平衡因子更改为1,BBST的深度增1;
  • BBST的根结点的平衡因子为1(左子树的深度大于右子树的深度):若BBST的左子树根结点的平衡因子为1,则需进行单向右旋平衡处理,并且在右旋处理之后,将根结点和其右子树根结点的平衡因子改为0,树的深度不变;

  若BBST的左子树根结点的平衡因子为-1,则需进行先向左、后向右双向旋转平衡处理,并且在旋转处理之后,修改根结点和其左、右子树节点的平衡因子,树的深度不变。

(4)若e的关键字大于BBST的根结点的关键字,而且在BBST的右子树中不存在和e 有相同关键字的结点,则将e插入在BBST右子树上,并且当插入之后的右子树深度增加(+1)时,分别就不同情况处理之。其处理操作和(三)中所述相对称。

1 //-------------------二叉排序树的类型定义-------------
2 typedef struct BSTNode{
3     ElemType  data;
4     int  bf;        //结点的平衡因子
5     struct BSTNode *lchild,*rchild;      //左、右孩子指针
6 }BSTNode,*BSTree;
1 //--------------------在平衡处理中进行右旋操作-------------------------
2 void R_Rotate(BSTree &p){
3     //对以*p为根的二叉排序树作右旋处理,处理之后p指向新的树根结点,即旋转处理之前的左子树的根结点
4     lc = p->lchild;        //lc指向的*p左子树根结点
5     p->lchild = lc->rchild;            //lc的右子树挂接为*p的左子树
6     lc->rchild = p;p = lc;            //p指向新的根结点
7 }//R_Rotate
1 //--------------------在平衡处理中进行左旋操作-------------------------
2 void L_Rotate(BSTree &p){
3     //对以*p为根的二叉排序树作左旋处理,处理之后p指向新的树根结点,即旋转处理之前的右子树的根结点
4     rc = p->rchild;            //rc指向的*p的右子树根结点
5     p->rchild = rc->lchild;        //rc的左子树挂接为*p的右子树
6     rc->lchild = p;p = rc;        //p指向新的根结点
7 }//L_Rotate
 1 //---------------------在平衡的二叉排序树BBST上插入一个新的数据元素e的递归算法-----------------
 2 #define LH +1             //左高
 3 #define EH 0                //等高
 4 #define RH -1               //右高
 5 Status InsertAVL(BSTree &T,ElemType e,Boolean &taller){
 6     //若在平衡的二叉排序树T中不存在和e有相同关键字的结点,则插入一个数据元素为e的新结点,并返回1,否则返回0.若因插入而使二叉排序树失去平衡,则作平衡旋转处理,布尔变量taller反映T长高与否
 7     if(!T){    //插入新结点,树”长高",置taller为TRUE
 8         T = (BSTree) malloc (sizeof(BSTNode));
 9         T->data = e;
10         T->lchild = T->rchild = NULL;
11         T->bf = EH;
12         taller = TRUE;
13     }
14     else {
15         if(EQ(e.key,T->data.key))        //树中已存在和e有相同关键字的结点
16             {taller = FALSE; return 0; }    //则不再插入
17         if (LT(e.key,T->data.key)){
18             if(!InsertAVL(T->lchild,e,taller))
19                 return 0;            //未插入
20             if(taller)                //已插入到*T的左子树中且左子树“长高”
21                 switch(T->bf){        //检查*T的平衡度
22                     case LH:            //原本左子树比右子树高,需要作左平衡处理
23                         LeftBalence(T); taller = FALSE;break;
24                     case EH:            //原本左、右子树等高,现因左子树增高而使树增高
25                         T->bf = LH;taller = TRUE; break;
26                     case RH:        //原本右子树比左子树高,现在左、右子树等高
27                         T->bf = EH;taller = FALSE; break;
28             }//switch(T->bf)
29         }//if
30         else {                                //应继续在*T的右子树中进行搜索
31             if(!InsertAVL(T->rchild,e,taller))
32                 return 0;                //未插入
33             if(taller)            //已插入到*T的右子树且右子树长高
34                 switch(T->bf){        //检查*T的平衡度
35                      case LH:            //原本左子树比右子树高,现在左、右子树等高
36                         T->bf = EH; taller = FALSE;break;
37                     case EH:            //原本左、右子树等高,现因右子树增高而使树增高
38                         T->bf =RH;taller = TRUE; break;
39                     case RH:        //原本右子树比左子树高,需要作右平衡处理
40                         RightBalance(T);taller = FALSE; break;
41             }//switch(T->bf)
42           }//else
43         }//else
44         return 1;
45 }//InsertAVL
//---------------左平衡处理的算法-------------------
void LeftBalace(BSTree &T){
    //对以指针T所指结点为根的二叉树作左平衡旋转处理,本算法结束时,指针T指向新的根结点
    lc = T->lchild;            //lc指向*T的左子树根结点
    switch(lc->bf){        //检查*T的左子树的平衡度,并作相应平衡处理
        case LH:        //新结点插入在*T的左孩子的左子树上,要作单右旋处理
            T->bf = lc->bf =EH;
            R_Rotate(T);    
            break;
        case RH:            //新结点插入在*T的左孩子的右子树上,要作双旋处理
            rd = lc->rchild;        //rd指向*T的左孩子的右子树根
            switch(rd->bf){        //修改*T及其左孩子的平衡因子
                case LH:T->bf = RH;  lc->bf = EH; break;
                case EH:T->bf = lc->bf = EH;        break;
                case RH:T->bf = EH;lc->bf = LH;   break;
            }//switch(rd->bf)
            rd->bf = EH;
            L_Rotate(T->lchild);        //对*T的左子树作左旋平衡处理
            R_Rotate(T);                    //对*T的右旋平衡处理
        }//switch(lc->bf)
  }//LeftBalance

8.平衡树查找的分析

  在平衡树上进行查找的时间复杂度为O(logn).

动态查找表

标签:

原文地址:http://www.cnblogs.com/wxb713/p/4340920.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!