數據結構的查找


1.  查找分類

        1.1  比較式查找法

                    1.1.1  線性表查找法

                                    1.1.1.1  順序查找法

                                    1.1.1.2  折半查找法

                                    1.1.1.3  分塊查找法

                    1.1.2  基於樹的查找法

                                    1.1.2.1  二叉排序樹

                                    1.1.2.2  平衡二叉樹

        1.2  計算式查找法

                    1.2.1  哈希查找法


2. 算法實例

         2.1  順序查找法

                思想:在表的一端設置監視哨(存放要查找的關鍵字),在表的另一段開始查找

                代碼實現 sequence.c(完整代碼)

/* 查找 key 鍵 */
int seq_search (RecordList l, int key) 
{
    /* 將鍵值設置在鏈的末端 */
    l.r[l.length].key = key;
    int     i;
    
    /* 順序查找 */
    for (i = 0; l.r[i].key != key; i++) ;
    return i;
}
              平均查找長度:ASL = (n+1)/2

        2.2  折半查找法(序列必須排序)

                思想:比較中間鍵值,如果小於則把左邊當作新序列比較中間鍵值,如果大於則把右邊當作新序列比較中間鍵值。

                代碼實現 binary.c(完整代碼)

/* 查找 key 鍵, l 中的 r 數組必須按照key值的字典順序排序 */
int binary_search (RecordList l, int key) 
{
    int     low = 0;
    int     high = l.length-1;

    while (low < high) {
        int     mid = (low + high)/2;
        if (key == l.r[mid].key) 
            return mid;
        else if (key < l.r[mid].key) 
            high = mid - 1;
        else 
            low = mid + 1;
    }
    
    return l.length;
}

              平均查找長度:ASL = log 2 (n+1) - 1



        2.3  分塊查找法

                思想:首先將列表分成若干個塊(子列表,塊間有序,快內無序),構造一個索引表,索引表按鍵值有序排列

                代碼實現 block.c(完整代碼)

int block_search (RecordList l, int key)
{
    BlockList (BLOCK_SIZE, l.length, 1); 

    int     i; 
    for (i = 0; i < block_list1.length; i++) {
        block_list1.r[i].addr = i * block_list1.block_length;
        block_list1.r[i].max_key = l.r[i*5].key;
    }

    for (i = 0; i < l.length; i++) 
        if (block_list1.r[i/5].max_key < l.r[i].key)
            block_list1.r[i/5].max_key = l.r[i].key;
    
    for (i = 0; i < block_list1.length; i++) {
        if (key < block_list1.r[i].max_key) {
            l.list_s = block_list1.r[i].addr;
            l.list_e = (i == block_list1.length-1 ? 
                        l.length : block_list1.r[i+1].addr-1);
            return seq_search (l, key);
        }
    }

    return l.length;
}
              平均查找長度:ASL = log 2 (n/s+1) + s/2             n 表示表的長度,s表示每塊中的

        2.4  二叉排序樹的查找法

                思想:key 和跟結點 t.key 比較 ,如果相等則返回根,小於進一步查左子樹,大於進一步查右子樹

                代碼實現 binary_tree.c(完整代碼)

/* 二叉排序樹的查找 */
BSTree BST_search (const BSTree root, int key) 
{
    if (!root) return NULL; 
    else if (root->data.key == key) 
        return root; 
    else if (key < root->data.key) 
        return BST_search (root->LChild, key); 
    else 
        return BST_search (root->RChild, key); 
} 


        2.5  平衡二叉樹(AVL樹)

               思想:對失衡節點進行順時針或逆時針旋轉

                           有四種形式:LL、LR、RR、RL

                                                   假設失衡節點爲 A、它的孩子節點中的某個爲B 、他的孩子的孩子節點中的某個節點爲C,

                                                   則:LL:(B爲A的左孩子)對A做一次順時針旋轉

                                                           RR:(B爲A的右孩子)對A做一次順時針旋轉

                                                           LR:(B爲A的左孩子,C爲B的右孩子)對B做一次逆時針旋轉,對A做一次順時針旋轉

                                                           RL:(B爲A的右孩子,C爲B的左孩子)對B做一次順時針旋轉,對A做一次、逆時針旋轉

                代碼實現 AVLTree.c(完整代碼)

/* 平衡二叉樹插入節點 */
void ins_AVLTree (AVLTree *avlt, int key)
{
    /* 初始化一個新節點 */
    AVLTNode    *S = (AVLTree)malloc (sizeof (AVLTNode));
    S->data.key = key;
    S->LChild = S->RChild = NULL;
    S->bf = 0;

    /* 插入 */
    if (!*avlt) 
        *avlt = S;
    else {
        /* 首先查找S的插入位置fp,同時記錄距S的插入位置最近且
         * 平衡因子不等於0(等於-1或1)的節點A, A可能爲失衡節點 */
        AVLTNode *A = *avlt, *FA = NULL;
        AVLTNode *p = *avlt, *fp = NULL;

        while (p) {
            if (p->bf) {
                A = p; 
                FA = fp;
            }
            fp = p;

            if (key < p->data.key) 
                p = p->LChild;
            else 
                p = p->RChild;
        }

        /* 插入S */
        if (key < fp->data.key) 
            fp->LChild = S; 
        else if (key > fp->data.key)
            fp->RChild = S; 
        else {
            free (S);
            return;
        }

        /* 確定節點B,並修改A的平衡因子 */ 
        AVLTNode    *B; 
        if (key < A->data.key) { 
            B = A->LChild; 
            A->bf += 1; 
        }else { 
            B = A->RChild; 
            A->bf -= 1; 
        }

        /* 修改B到S路徑上各節點的平衡因子 */
        p = B; 
        while (p != S) { 
            if (key < p->data.key) { 
                p->bf = 1; 
                p = p->LChild; 
            }else { 
                p->bf = -1; 
                p = p->RChild; 
            }
        } 

        /* 判斷失衡類型並做相應處理 */
        /* LL型 */
        if (2 == A->bf && 1 == B->bf) {
            /* A做一次順時針旋轉 */
            B = A->LChild;
            A->LChild = B->RChild;
            B->RChild = A;
            A->bf = B->bf = 0; 

            if (!FA) 
                *avlt = B;
            else if (A == FA->LChild)
                FA->LChild = B;
            else 
                FA->RChild = B;
        } /* LR型 */
        else if (2 == A->bf && -1 == B->bf) {
            AVLTNode *C;
            /* 先對B做一次逆時針旋轉,再對A做一次順時針旋轉 */
            B = A->LChild;
            C = B->RChild;
            B->RChild = C->LChild;
            A->LChild = C->RChild;
            C->LChild = B;
            C->RChild = A;

            if (S->data.key < C->data.key) {
                A->bf = -1; B->bf = C->bf = 0;
            }else if (S->data.key > C->data.key) {
                B->bf = 1; A->bf = C->bf = 0;
            }else 
                A->bf = B->bf = 0; 

            if (!FA) 
                *avlt = S;
            else if (A == FA->LChild) 
                FA->LChild = C;
            else 
                FA->RChild = C;
        } /* RL型 */
        else if (-2 == A->bf && 1 == B->bf) {
            AVLTNode *C;
            /* 先對B做一次順時針旋轉,再對A做一次逆時針旋轉 */ 
            B = A->RChild;
            C = B->LChild;
            B->LChild = C->RChild;
            A->RChild = C->LChild;
            C->LChild = A;
            C->RChild = B;

            if (S->data.key < C->data.key) {
                B->bf = -1; A->bf = C->bf = 0;
            }else if (S->data.key > C->data.key) {
                A->bf = 1; B->bf = C->bf = 0;
            }else 
                A->bf = B->bf = 0;

            if (!FA) 
                *avlt = S;
            else if (A == FA->LChild) 
                FA->LChild = C;
            else 
                FA->RChild = C;
        } /* RR 型 */
        else if (-2 == A->bf && -1 == B->bf) {
            /* 對A做一次逆時針旋轉 */
            B = A->RChild;
            A->RChild = B->LChild;
            B->LChild = A;
            A->bf = B->bf = 0;

            if (!FA) 
                *avlt = B;
            else if (A == FA->LChild) 
                FA->LChild = B;
            else 
                FA->RChild = B;
        }
    }
}
              時間複雜度:O(log 2 n)




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章