wly603

查找方法--从静态表到动态表

概要:

    数据结构学习的笔记:查找的一些方法。各种方法的具体描述和特点,烦请参考数据结构的课本,或直接google

    针对数据存储结构的不一样,查表方法分为:

              静态表:顺序,折半,分块查找

              动态表:二叉排序树、平衡二叉树

一、具体方法介绍

     1、针对静态表

     (法1)顺序查找:适合于存储结构为顺序存储或链接存储的线性表。

       

顺序查找
/*
  顺序查找
      适合于存储结构为顺序存储或链接存储的线性表。
  
    查找关键字为key 的记录
    输入:待查数组  s[0]----s[n-1],共n个数
    输出:成功,返回序号
          失败,返回-1
*/

int Search_Seq(int *s,int key, int n )
{
    int i=0;

    while( i<n && s[i] != key)  //不如书上的优化
        i++;

    if (s[i] == key)
    {
        return i;
    }
    else
        return -1;
}

 (法2)折半查找:适用于有序表,且只能是顺序存储结构

    

折半查找
/*
    折半查找
       适用于有序表,且只能是顺序存储结构

   实现:
      递归:Search_Bin_Rec
      非递归:Search_Bin_NoRec
*/
int Search_Bin_NoRec(int *s,int key, int n)
{
    int low = 0;
    int high = n-1;
    int mid = 0;

    while ( low<= high)
    {
        mid = (low+high)/2;

        if (s[mid] == key)  //查找到了,直接返回序号
        {
            return mid;
        }
        else if (s[mid]>key)
        {
            high = mid -1;
        }
        else
            low = mid +1;
    }
    return -1;//查找失败
}

//递归实现,这里跟4个参数
int Search_Bin_Rec(int *s,int key,int low,int high)
{
    if (low>high)
        return -1;


    int mid = (low+high)/2;

    if (s[mid] == key)
    {
        return mid;
    }
    else
        if (s[mid]>key)
        {
            return(Search_Bin_Rec(s,key,low,mid-1));
        }
        else
            return(Search_Bin_Rec(s,key,mid+1,high));

}

(法3)分块查找:

分块查找
/*
   分块查找
*/
typedef struct  
{
    int key;
    int link;
}IntexType;  //索引表元素的结构

int Search_Blk(IntexType *idx,int *s,int key,int nIdx)
{
    //先用折半查找法,在有序的索引表中找到块
    int low=0,high=nIdx-1,mid=0;
    bool findBlock_flag = false;

    int blockStart=0,blockEnd=0;//记录块的起始位置和终止位置

    if (key > idx[high].key)//比最大的还要大,查找失败
    {
        return -1;
    }

    while (low<=high && !findBlock_flag)
    {
        mid = (low+high)/2;

        if (idx[mid].key == key)//找到分块
        {
            blockStart = idx[mid].link;
            blockEnd = idx[mid+1].link - 1;

            findBlock_flag = true;
        }
        else
            if (idx[mid].key > key)
            {
                high = mid -1;
            }
            else
                low = mid +1;

        if (low >high)
        {
            findBlock_flag = true;   //找到分块
                
            blockStart = idx[mid].link;
            blockEnd = idx[mid+1].link - 1;
        }
    }



    //找到块了(blockStart, blockEnd),再进行顺序查找
    cout<<"位于: "<<blockStart<<"  "<<blockEnd<<endl;
    int i=blockStart;
    while(i<=blockEnd && s[i] != key)
        i++;

    if (s[i] == key)
    {
        return i;   //查找成功
    }
    else
        return -1;//查找失败

}

 

2、针对动态表

   动态表: 二叉排序树

   

二叉排序树
/*
  动态表: 二叉排序树
*/
typedef struct node
{
    int data;
    struct node *lchild;
    struct node *rchild;
}BSTnode;   //二叉排序树的结点

//中序遍历 二叉树,得到的是递增的序列。  可用于检验构造二叉树是否成功?!
void InOrderTraverse_Recur(BSTnode *T)
{
    if ( T != NULL)
    {
        InOrderTraverse_Recur(T->lchild);
        printf("%d \t",T->data);
        InOrderTraverse_Recur(T->rchild);
    }
}

//二叉排序树插入操作,     注意:涉及到修改时,参数一定要用引用或者是二级指针。
//当二叉排序树中不存在关键字时,将其插入到二叉排序树
bool InsertBST(BSTnode *&T, int key)
{
    if (T == NULL)
    {
        T = (BSTnode*)malloc(sizeof(BSTnode));
        T->lchild = T->rchild = NULL;
        T->data = key;

        return true;  //二叉树中无关键字相同的点,插入成功
    }
    else
    {
        if ( key == T->data)  //二叉树中已经有了关键字相同的点,不再插入
            return false;        
        else if ( key < T->data)   //小于,则插入到左子树
            return(InsertBST(T->lchild,key));
        else
            return(InsertBST(T->rchild,key));//大于,则插入到左子树
    }    

}

/*
二叉排序树的生成,
  是从空的二叉排序树开始,每输入一个结点数据,就调用一次插入算法将它插入到当前已生成的二叉排序树中
*/
//输入序列,构造二叉排序树
BSTnode * CreatBST(int *s,int n)
{
    BSTnode * T= NULL;

    int i=0,key;
    while (i<n)
    {
        key = s[i];
        InsertBST(T,key);    
        i++;
    }

    printf("\n构造二叉排序树成功!!\n");
    return T;
}

//二叉树的查找
//已经建立好了二叉树,查找关键字key是否成功
//参数:二叉排序树,待查找关键字,查找结束后指向关键字的指针
//不成功,则插入,返回false;否则,返回true
bool SearchBST(BSTnode *&T, int key,BSTnode *&pKey )
{
    if (T == NULL)  //为空,则查找失败,进行插入操作
    {
        InsertBST(T,key);  //这里进行了插入,相当于修改了二叉树,故SearchBST 参数使用引用
        pKey = T;
        return false;
    }
    else
    {
        if ( key == T->data)
        {
            pKey = T;
            return true;
        }
        else if ( key < T->data)
            return(SearchBST(T->lchild,key,pKey));
        else
            return(SearchBST(T->rchild,key,pKey));        

    }
}

//删除二叉排序树中关键字为key的节点
/* 
   删除关键字为key的结点,删除成功,返回true。否则,返回false(即没有关键字为key的结点)
*/
//已找到结点,直接删除结点的具体实现。注意:分为2种情况:有子树为空   2个子树均为非空
void DeleteNode(BSTnode*&T)
{
    BSTnode *temp=NULL; 
    
    if (!T->lchild)  //左子树为空
    {
        temp = T;//记录要删除的结点
        T = T->rchild;//重接右子树
        
        free(temp);
        temp = NULL;        
    }
    else if (!T->rchild)//右子树为空
    {
        temp = T;
        T = T->lchild;//重接左子树
        
        free(temp);
        temp = NULL;
    }
    else  //左右子树均非空
    {
        
        BSTnode *s=NULL,*parent=NULL;  //s为直接前驱,parent为直接前驱的双亲
        
        parent = T;
        s = T->lchild;//转左
        
        while (s->rchild)  //向右走到底,找中序遍历的直接前驱s
        {
            parent = s;
            s = s->rchild;
        }
        
        T->data = s->data;  //把直接前驱的数据 给要删除的结点
        
        //判断是否转左,进行重接直接前驱s的左子树
        if (parent == T)//没有转左
        {
            parent->lchild = s->lchild;//或者T->lchild = s->lchild 
            
            free(s);
            s = NULL;
        }
        else
        {
            parent->rchild = s->lchild;
            
            free(s);
            s = NULL;
        }
        
        
    }
}
//删除,包含查找关键字结点。
bool DeleteBST(BSTnode*&T,int key)
{
    if (!T)
    {
        return false;
    }
    else
    {
        if (key == T->data)
        {
            DeleteNode(T);
            return true;
        }
        else if (key < T->data)
            return(DeleteBST(T->lchild,key));
        else
            return(DeleteBST(T->rchild,key));
        
    }
}

 

 平衡二叉树:为了保证二叉排序树的性能,应该减少二叉排序树的深度。因此要构建平衡二叉树

         参考:!!(好!) http://webtrados.llh4.com/post/522.html
                         http://hxraid.iteye.com/blog/609949
                      动画演示:http://webtrados.llh4.com/post/522.html

平衡二叉树
/*
   为了保证二叉排序树的性能,应该减少二叉排序树的深度。因此要构建平衡二叉树
   参考:!!(好!)  http://webtrados.llh4.com/post/522.html
        http://hxraid.iteye.com/blog/609949
      动画演示:http://webtrados.llh4.com/post/522.html

    平衡二叉树的操作
*/
//平衡二叉树,结点的结构
typedef struct  AVLNODE
{
    int data;
    int bf;        //结点的平衡因子
    struct AVLNODE *lchild,*rchild;
}AVLNode;

//中序遍历 平衡二叉树,得到的是递增的序列。  可用于检验构造二叉树是否成功?!
void InOrderTraverseAVLTree_Recur(AVLNode*T)
{
    if ( T != NULL)
    {
        InOrderTraverseAVLTree_Recur(T->lchild);
        printf("%d \t",T->data);
        InOrderTraverseAVLTree_Recur(T->rchild);
    }
}
//单向右旋处理
void  R_Rotate(AVLNode* &T)
{
    AVLNode* tempLc = T->lchild;//tempLc 指向根的左孩子

    T->lchild = tempLc->rchild;
    tempLc->rchild = T;

    T = tempLc;  //T继续指向根结点(新)
}

//单向左旋处理
void L_Rotate(AVLNode *&T)
{
    AVLNode* tempRc = T->rchild;  //tempRc 指向根的右孩子

    T->rchild = tempRc->lchild;
    tempRc->lchild = T;

    T = tempRc;
}

#define   LH  1     //左高
#define   EH  0     //等高
#define   RH  -1    //右高
 
void LeftBalance(AVLNode*&T)//先左后右处理(或者直接右旋处理)
{
    AVLNode* lc = T->lchild;//当前根(T)的左孩子lc
    AVLNode *rd = NULL;  //调整后新的根节点

    switch (lc->bf)
    {
    case LH:                   //直接右旋处理
        T->bf = lc->bf = EH;//平衡因子都修改为0
        R_Rotate(T);
        break;
    case RH:       //先左旋后右旋
        {
            rd = lc->rchild; //

            switch (rd->bf) //为了修改旋转后的平衡因子
            {
            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);
            R_Rotate(T);

            break;        
        }
    }//switch(lc->bf)
}

void RightBalance(AVLNode* &T)//先右后左处理(或者直接左旋转处理)
{
    AVLNode *rc,*ld;

    rc = T->rchild;

    switch(rc->bf)
    {
    case RH:
        T->bf = rc->bf = EH;
        L_Rotate(T);
        break;
    case LH:
        {
            ld = rc->lchild;

            switch (ld->bf)
            {
            case LH:
                T->bf = EH;
                rc->bf = RH;
                break;
            case EH:
                T->bf = rc->bf = EH;
                break;
            case RH:
                T->bf = LH;
                rc->bf = EH;
                break;
            }//    switch (ld->bf)

            ld->bf = EH;
            R_Rotate(T->rchild);
            L_Rotate(T);

            break;
        }
    }//switch(rc->bf)
        
}

//在二叉平衡树中插入关键字为e的结点。若插入操作引起二叉树失衡,则进行平衡旋转处理,taller反映T长高与否
//不存在关键字为e的结点,则插入,返回1  否则,返回0
int InsertAVL(AVLNode*&T,int e,bool &taller)
{
    if (!T)
    {
        T = (AVLNode*)malloc(sizeof(AVLNode));
        T->bf = EH;
        T->data = e;
        T->lchild = T->rchild = NULL;
        taller = true;

        return 1;
    }
    
    if (e == T->data)
    {
        taller = false;
        return 0;
    }
    else if ( e < T->data)  //插入到左子树
    {
        if(!InsertAVL(T->lchild,e,taller))// 未插入结点,直接返回。
            return 0; 
        //否则,要进行平衡旋转二叉树处理 
        if (taller)
        {
            switch (T->bf)
            {
            case LH:
                LeftBalance(T);
                taller = false;
                break;
            case RH:
                taller = false;
                T->bf = EH;
                break;
            case EH:
                T->bf = LH;
                taller = true;
                break;
            }
        }

        return 1;
    }
    else   //插入到右子树
    {
        if (!InsertAVL(T->rchild,e,taller)) //未插入
        {
            return 0;
        }
        if (taller) //插入成功
        {
            switch (T->bf)
            {
            case LH:
                T->bf = EH;
                taller = false;
                break;
            case EH:
                T->bf = RH;
                taller = true;
                break;
            case RH:
                RightBalance(T);
                taller = false;
                break;

            }
        }

        return 1;

    }

}

主函数测试:

主函数main
void main()
{
    const n = 10;
    int key=58;

    int a[n] = {32,5,10,8,200,50,36,20,150,96};
//    cout<<Search_Seq(a,key,n)<<endl;
//    cout<<Search_Bin_NoRec(a,key,n)<<endl;
//    cout<<Search_Bin_Rec(a,key,0,n-1)<<endl;

    //分块查找测试
    int aBlack[16] = {9,22,12,14,
                      35,42,44,38,
                      48,60,58,47,
                      78,80,77,82};
    IntexType idx[4] = {{22,0},{44,4},{60,8},{82,12}};  //索引表

//    cout<<Search_Blk(idx,aBlack,key,4)<<endl;


    //二叉排序树 查找
    BSTnode * BST_main = NULL,*pTemp=NULL;
    BST_main = CreatBST(a,n);
    InOrderTraverse_Recur(BST_main);

    if(SearchBST(BST_main,80,pTemp))
        cout<<"查找成功!!"<<endl<<pTemp->data<<endl;
    else
        cout<<"查找失败!!"<<endl<<pTemp->data<<endl;

    InOrderTraverse_Recur(BST_main);


    

    //删除结点   测试
    if (DeleteBST(BST_main,5))
    {
        cout<<"删除结点成功"<<endl;
        InOrderTraverse_Recur(BST_main);
    }
    else
        cout<<"删除失败!!"<<endl;


    //平衡二叉树的测试
    AVLNode * AVLTree = NULL;
    bool taller = false;

    cout<<endl<<"构造平衡二叉树实验:  "<<endl;

    for (int i=0;i<n;i++)
    {
        InsertAVL(AVLTree,a[i],taller);    
        
        InOrderTraverseAVLTree_Recur(AVLTree);

        printf("\n");
    }

    int xa = sizeof(int);
}

 

(完)

 

 

posted on 2012-05-08 12:22  wly603  阅读(533)  评论(0编辑  收藏  举报

导航