1. 程式人生 > >資料結構知識整理 - 折半查詢

資料結構知識整理 - 折半查詢

主要內容


 

基本概念

在介紹查詢演算法前我們先重溫幾個重要概念

1)資料客觀事物的符號表示,是所有能輸入到計算機中,並能被計算機程式處理的符號的總稱。如數學計算中用到的整數實數,文字編輯中用到的字串,多媒體程式處理的圖形影象聲音動畫等通過特殊編碼定義後的資料。

2)資料元素資料的基本單位,在計算機中通常作為一個整體進行考慮和處理。資料元素也稱記錄,用於描述一個完整的物件,該物件可以是一名學生的資訊(記錄),某一次棋局,圖中的某一個頂點等。

3)資料項組成資料元素的、有獨立含義的、不可分割的最小單位

。如學生記錄中的學號、姓名、性別等都屬於資料項。

4)資料結構相互之間存在一種或多種特定關係的資料元素的集合。資料結構包括邏輯結構(邏輯表示)和儲存結構(物理實現)。

5)查詢表同一型別的資料元素(或記錄)構成的集合,可以由線性表、樹結構等多種資料結構來實現。

6)關鍵字資料元素(或記錄)中的某個資料項的值,相當於“資料庫”知識中一行記錄的主碼(PRIMARY KEY)。

typedef struct          /*定義資料元素結構體*/
{
    KeyType key;        /*關鍵字*/
    OtherType other;    /*其他資料項*/
} Element;


typedef struct          /*以順序表結構定義查詢表*/
{
    /*順序表藉助陣列儲存資料,因此需要空間基地址base(陣列頭)和當前長度length(陣列長度)*/
    Element *base;      
    int length;
} SSTable;              /*SSTable表示順序查詢表*/

7)查詢根據給定的某個值,在查詢表中確定一個其關鍵字等於給定值的資料元素(或記錄)。同樣可以類比資料庫的資料查詢針對不同的資料結構,查詢演算法也會有所不同。

8)平均查詢長度衡量查詢演算法效能的一個標準。


 

在查詢表的資料結構中,線性表是最簡單的一種。

線性表查詢又分為順序查詢折半查詢分塊查詢

 

折半查詢(Binary Search)

顧名思義,折半查詢每一次查詢比較都能使查詢範圍縮小一半,它是一種效率較高的查詢方法。

但是折半查詢要求線性表必須採用順序儲存結構,而且表中元素必須按關鍵字有序排列(有點類似資料庫的索引)。

為了標記出查詢範圍,我們要設定三個變數low、high、middle分別表示查詢範圍的下界、上界和中間位置(每次查詢後更新賦值)。

 

提前路過的圈毛君:“總是一不留心就把“查詢”寫成了“查詢”(資料庫留下的習慣),雖然這兩個詞意思一樣,但無奈博主是強迫症_(:з」∠)_喜歡維持前後文的用詞一致性。”

 

下面給出非遞迴演算法的程式碼:

int Bin_Search(SSTable t, KeyType key)
{
    int low = 1, high = t.length;
    
    while(low <= high)
    {
        int mid = (low + high) / 2;    

        if(t.base[mid] == key) return mid;

        else if(t.base[mid] < key) low = mid+1;
    
        else high = mid-1;
    }

    return 0;
}

 

在每次迴圈中,low、high、mid中的其中兩個值都要作更新,而且這個不斷縮小查詢範圍的過程也很像一個不斷深入、細化的樹或圖的遍歷過程,因此我們很容易想到一個詞——遞迴

下面給出折半查詢的遞迴演算法的實現:

int Bin_Search(SSTable t, KeyType key, int low, int high)
{
    if(low <= high)
    {
        int mid = (low + high) / 2;
        if(t.base[mid] == key) return mid;
        else if(t.base[mid] < key) low = mid + 1;
        else high = mid-1;
    }

    Bin_Search(t, key, low, high);
}

折半查詢過程可用二叉樹來描述,由此得到的二叉樹稱為判定樹。藉助判定樹可以很快求出折半查詢的平均查詢長度。

 

優點

查詢效率比順序查詢高,時間複雜度為O(log2n)。

缺點:

只適用於順序儲存結構的有序表,所以查詢前必須先對錶進行排序,而排序本身就是一種費時的運算。而且,對於有序表並不方便進行插入、刪除操作,因此折半查詢不適用於資料元素經常發生變動的查詢表。