二分查找也稱折半查找(Binary Search),它是一種效率較高的查找方法。可是,折半查找要求線性表必須採用順序存儲結構,並且表中元素按關鍵字有序排列。
從上面的定義咱們能夠知道,知足該算法的要求必須以下兩點:算法
其實,二分查找也仍是比較容易理解的,大概就是一分爲二,而後兩邊比較,保留有效區間,繼續一分爲二查找,直到找到或者超出區間則結束,因此二分查找的基本步驟是:數組
這裏,我主要採用遞歸和非遞歸兩種方法實現,具體以下:url
首先第一種是非遞歸的算法實現,算法以下:spa
/** * 二分查找算法 * @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; }
而後第二種是遞歸的算法實現,算法以下:code
/** * @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)的所在位置,因此,調用算法查找以下:blog
// 待查找區間 $arr = [1, 3, 7, 9, 11, 57, 63, 99]; // 非遞歸查找57所在的位置 $find_key = binary_search($arr, 57); // 遞歸查找57所在的位置 $find_key_r = binary_search_recursion($arr, 57, 0, count($arr)); // 輸出打印 print_r($find_key); print_r($find_key_r);
在有序數組中若是用暴力的算法去查找,也就是逐個遍歷比較,那麼時間複雜度是O(n);可是,用二分查找後,由於每次能夠捨去一半查找區間,因此會將時間複雜度減小到O(logn),算法更優。遞歸
又到了無聊的客套話時間,老規律,有問題直接留言,有想法直接說,有錯誤直接提出來,我都會及時回覆的,謝謝。rem