1. 程式人生 > >Wonder233的學習部落格

Wonder233的學習部落格

折半查詢(二分查詢)

概念

每次取中間記錄查詢的方法。

前提

線性表中的記錄必須是關鍵碼有序(通常從小到大有序),線性表必須採用順序儲存。

基本思想

在有序表中,取中間記錄作為比較物件:

  • 若給定值與中間記錄的關鍵字相等,則查詢成功;
  • 若給定值小於中間記錄的關鍵字,則在中間記錄的左半區繼續查詢;
  • 若給定值大於中間記錄的關鍵字,則在中間記錄的右半區繼續查詢。

不斷重複上述過程,直到查詢成功,或所有查詢區域無記錄,查詢失敗為止。

演算法實現

function Binary_Search(a,key){
    var low,high,mid;
    low = 0
; /* 定義最低下標為記錄首 */ high = a.length-1; /* 定義最高下標為記錄尾 */ while (low <= high) { mid = parseInt((low + high) / 2); /* 折半 */ if (key < a[mid]) { /* 若查詢值比中值小 */ high = mid - 1; /* 最高下表調整到中間下標小一位 */ }else if(key >a[mid]){ /* 若查詢值比中值大 */ low = mid + 1; /* 最低下表調整到中間下標大一位 */
}else{ return mid; /* 若相等則說明 mid 即為查詢到的位置 */ } } return a.length; /* 返回原陣列長度則說明查詢失敗 */ }

時間複雜度分析

折半演算法的時間複雜度為 O(logn)

對於需要頻繁執行插入或刪除操作的資料集來說,維護有序的排序會帶來不小的工作量,因此不建議使用折半演算法。

插值查詢

基本思想

折半查詢最關鍵的一段程式碼就是求中間值:

mid=low+high2=low+12(highlow)
也就是 mid 等於最低下標 l
ow
加上最高下標 highlow 的差的一半。
考慮將這個 12 改進為下面的計算方案:mid=low+keya[low]a[high]a[low](highlow)
假設a[11]=1,16,24,35,47,59,62,73,88,99low=0high=9a[low]=0a[high]=99,如果要找的是 key=16,按照折半的做法,需要四次才可以得到結果。
但如果用新方法:keya[low]a[high]a[low]=1619910.153mid1+0.153×(90)=2.377,取整 mid=2,則只需要兩次就查詢到結果了,大大提高了查詢的效率。

插值查詢是根據要查詢的關鍵字 key 與查詢表中最大最小記錄的關鍵字比較後的查詢方法,其核心就在於插值的計算公式:keya[low]a[high]a[low]

演算法實現

/* 插值查詢 */
function Interpolation_search(a,key){
    var low,high,mid;
    low = 0; /* 定義最低下標為記錄首 */
    high = a.length-1; /* 定義最高下標為記錄尾 */
    while (low <= high) {
        mid = parseInt(low + (key -a[low]) / (a[high]-a[low])*(high-low)); /* 插值 */
        if (key < a[mid]) { /* 若查詢值比中值小 */
            high = mid - 1; /* 最高下表調整到中間下標小一位 */
        }else if(key >a[mid]){ /* 若查詢值比中值大 */
            low = mid + 1; /* 最低下表調整到中間下標大一位 */
        }else{
            return mid; /* 若相等則說明 mid 即為查詢到的位置 */
        }
    }
    return a.length; /* 返回原陣列長度則說明查詢失敗 */
}

時間複雜度分析

也是O(logn)。但對於表長較長,而關鍵字分佈又比較均勻的查詢表來說,插值查詢演算法的平均效能比折半查詢要好得多。