1. 程式人生 > >PHP演算法之二分查詢

PHP演算法之二分查詢

page_img_url

二分查詢的定義

二分查詢也稱折半查詢(Binary Search),它是一種效率較高的查詢方法。但是,折半查詢要求線性表必須採用順序儲存結構,而且表中元素按關鍵字有序排列。

演算法的要求

從上面的定義我們可以知道,滿足該演算法的要求必須如下兩點:

  1. 必須採用順序儲存結構。
  2. 必須按關鍵字大小有序排列。

演算法的步驟

其實,二分查詢也還是比較容易理解的,大概就是一分為二,然後兩邊比較,保留有效區間,繼續一分為二查詢,直到找到或者超出區間則結束,所以二分查詢的基本步驟是:

  1. 確定要查詢的區間
  2. 確定要二分時的參照點
  3. 區間內選取二分點
  4. 根據二分點的值,綜合左右區間情況以及求解的目的,捨去一半無用的區間
  5. 繼續在有效區間重複上面的步驟

演算法原始碼

這裡,我主要採用遞迴和非遞迴兩種方法實現,具體如下:

首先第一種是非遞迴的演算法實現,演算法如下:

/**
 * 二分查詢演算法
 * @param array $arr 待查詢區間
 * @param int $number 查詢數
 * @return int        返回找到的鍵
 */
function binary_search($arr, $number) {
    // 非陣列或者陣列為空,直接返回-1
    if (!is_array($arr) || empty($arr)) {
        return -1;
    }
    // 初始變數值
    $len = count($arr);
    $lower = 0;
    $high = $len - 1;
    // 最低點比最高點大就退出
    while ($lower <= $high) {
        // 以中間點作為參照點比較
        $middle = intval(($lower + $high) / 2);
        if ($arr[$middle] > $number) {
            // 查詢數比參照點小,捨去右邊
            $high = $middle - 1;
        } else if ($arr[$middle] < $number) {
            // 查詢數比參照點大,捨去左邊
            $lower = $middle + 1;
        } else {
            // 查詢數與參照點相等,則找到返回
            return $middle;
        }
    }
    // 未找到,返回-1
    return -1;
}

然後第二種是遞迴的演算法實現,演算法如下:

/**
 * @param array $arr 待查詢區間
 * @param int $number 查詢數
 * @param int $lower 區間最低點
 * @param int $high 區間最高點
 * @return int
 */
function binary_search_recursion(&$arr, $number, $lower, $high) {
    // 以區間的中間點作為參照點比較
    $middle = intval(($lower + $high) / 2);
    // 最低點比最高點大就退出
    if ($lower > $high) {
        return -1;
    }
    if ($number > $arr[$middle]) {
        // 查詢數比參照點大,捨去左邊繼續查詢
        return binary_search_recursion($arr, $number, $middle + 1, $high);
    } elseif ($number < $arr[$middle]) {
        // 查詢數比參照點小,捨去右邊繼續查詢
        return binary_search_recursion($arr, $number, $lower, $middle - 1);
    } else {
        return $middle;
    }
}

演算法的使用

需求是在一個排列好的區間($arr)中,查詢一個數($number)的所在位置,所以,呼叫演算法查詢如下:

// 待查詢區間
$arr = [1, 3, 7, 9, 11, 57, 63, 99];
// 非遞迴查詢66所在的位置
$find_key = binary_search($arr, 57);
// 遞迴查詢66所在的位置
$find_key_r = binary_search_recursion($arr, 57, 0, count($arr));
// 輸出列印
print_r($find_key);
print_r($find_key_r);

時間複雜度分析

在有序陣列中如果用暴力的演算法去查詢,也就是逐個遍歷比較,那麼時間複雜度是O(n);但是,用二分查詢後,因為每次可以捨去一半查詢區間,所以會將時間複雜度減少到O(logn),演算法更優。

最後

又到了無聊的客套話時間,老規律,有問題直接留言,有想法直接說,有錯誤直接提出來,我都會及時回覆的,謝謝。