1. 程式人生 > >三種靜態查詢演算法:順序、二分/折半、索引/分塊查詢

三種靜態查詢演算法:順序、二分/折半、索引/分塊查詢

  終於找了個時間,把三種靜態查詢演算法簡單總結了一下,與大家分享討論。

順序查詢

簡介

  順序查詢是在一個已知無(或有序)序佇列中找出與給定關鍵字相同的數的具體位置。原理是讓關鍵字與佇列中的數逐個比較,直到找出與給定關鍵字相同的數為止。

程式碼實現

public static int orderSearch(int arr[], int target) {
        for (int i = 0; i < arr.length; i++)
            if (arr[i] == target)
                return
i; return -1; }

效能分析

  時間複雜度O(n)

二分/折半查詢

簡介

  二分查詢又稱折半查詢,優點是比較次數少,查詢速度快,平均效能好;其缺點是要求待查表為有序表,且插入刪除困難。

  因此,折半查詢方法適用於不經常變動而查詢頻繁的有序列表。

  兩個條件:1)序列有序;2)可以隨機訪問

查詢過程

  首先,假設表中元素是按升序排列,將表中間位置記錄的關鍵字與查詢關鍵字比較,如果兩者相等,則查詢成功;否則利用中間位置記錄將表分成前、後兩個子表,如果中間位置記錄的關鍵字大於查詢關鍵字,則進一步查詢前一子表,否則進一步查詢後一子表。重複以上過程,直到找到滿足條件的記錄,使查詢成功,或直到子表不存在為止,此時查詢不成功。

程式碼實現

public static int biSearch(int arr[], int target) {
        int low = 0, high = arr.length - 1;
        int mid;
        while (low <= high) {
            mid = low + (high - low) / 2;
            if (arr[mid] == target)
                return mid;
            else if (arr[mid] < target)
                low = mid + 1
; else high = mid - 1; } return -1; }

效能分析

時間複雜度:

因為二分查詢每次排除掉一半的不適合值,所以對於n個元素的情況:

一次二分剩下:n/2 
兩次二分剩下:n/2/2 = n/4 
……. 
m次二分剩下:n/(2^m)
在最壞情況下是在排除到只剩下最後一個值之後得到結果,即
n/(2^m)=1

所以由上式可得 : 2^m=n

進而可求出時間複雜度為: log2(n)

分塊/索引查詢

簡介

  分塊查詢是折半查詢和順序查詢的一種改進方法,分塊查詢由於只要求索引表是有序的,對塊內節點沒有排序要求(塊內無序,塊間有序),因此特別適合於節點動態變化的情況。

  折半查詢雖然具有很好的效能,但其前提條件時線性表順序儲存而且按照關鍵碼排序,這一前提條件在結點樹很大且表元素動態變化時是難以滿足的。而順序查詢可以解決表元素動態變化的要求,但查詢效率很低。如果既要保持對線性表的查詢具有較快的速度,又要能夠滿足表元素動態變化的要求,則可採用分塊查詢的方法。

  當增加或減少節以及節點的關鍵碼改變時,只需將該節點調整到所在的塊即可。在空間複雜性上,分塊查詢的主要代價是增加了一個輔助陣列。

方法描述

  分塊查詢要求把一個大的線性表分解成若干塊,每塊中的節點可以任意存放,但塊與塊之間必須排序。假設是按關鍵碼值非遞減的,那麼這種塊與塊之間必須滿足已排序要求,實際上就是對於任意的i,第i塊中的所有節點的關鍵碼值都必須小於第i+1塊中的所有節點的關鍵碼值。還要建立一個索引表(索引表中為每一塊都設定索引項,每一個索引項都包含兩個內容)

  • 該塊的起始地址
  • 該塊中最大的元素

  比如:

image

  顯然,索引表是按關鍵字非遞減順序排列的。

  一般先用二分查詢索引表,確定需要查詢的關鍵字在哪一塊,然後再在相應的塊內用順序查詢。

程式碼實現

    public boolean search(int data) {
        int i = binarysearch(data);// 先二分查詢確定在哪個塊
        for (int j = 0; j < list[i].size(); j++) {// 然後順序查詢在該塊內哪個位置
            if (data == (int) list[i].get(j)) {
                System.out.println(String.format("查詢元素為  %d 第: %d塊  第%d個 元素",data, i + 1, j + 1));
                return true;
            }
        }
        return false;
    }

    /**
     * 二分查詢
     */
    private int binarysearch(int value) {
        int start = 0;
        int end = index.length;
        int mid = -1;
        while (start <= end) {
            mid = start + (end - start) / 2;
            if (index[mid] > value) {
                end = mid - 1;
            } else {
                start = mid + 1;// 如果相等,也插入後面
            }
        }
        return start;
    }

效能分析

  這種帶索引表的分塊有序表查詢的時間效能取決於兩步查詢時間之和:如前面所述,第一步可以採用簡單順序查詢和折半查詢之一進行。第二步只能採用簡單順序查詢,但由於子表的長度較原表的長度小。因此,其時間效能介於順序查詢和折半查詢之間。

  假設索引表有n個元素,每塊含有s個元素,平均查詢長度為:ASL=(n/s+s)/2 +1,時間複雜度為O(n)~O(log2n)

綜合比較

null 順序查詢 二分查詢 分塊查詢
表的結構 有序、無序 有序 塊內無序、塊間有序
表的儲存 順序、鏈式 順序 順序、鏈式
平均查詢長度 最大 最小 中間
時間複雜度 O(n) O(log2n) 中間

—–樂於分享,共同進步
—–Any comments greatly appreciated