算法筆記-二分查找
阿新 • • 發佈:2019-02-01
str 指定元素 auth 排序 條件 通過 req 有序數組 中間
【二分查找】
二分查找針對的是一個有序的數據集合,查找思想有點類似分治思想。每次都通過跟區間的中間元素對比,將待查找的區間縮小為之前的一半,直到找到要查找的元素,或者區間被縮小為 0。
二分查找是一種非常高效的查找算法,時間復雜度是 O(logn)。O(logn) 這種對數時間復雜度,是一種極其高效的時間復雜度,有的時候甚至比時間復雜度是常量級O(1) 的算法還要高效。二分查找更適合處理靜態數據,也就是沒有頻繁的數據插入、刪除操作。
使用循環和遞歸都可以實現二分查找。
二分查找應用場景的局限性:
- 二分查找依賴的是順序表結構,簡單點說就是數組。(鏈表不可以)
- 二分查找針對的是有序數據。(如果數據沒有序,我們需要先排序。)
- 數據量太大不適合二分查找。
<?php /** * 二分查找 查找=find的元素 * @param array $numbers * @param [type] $find*/ function binarySearch(array $numbers, $find) { $low = 0; $high = count($numbers) - 1; return search($numbers, $low, $high, $find); } function search(array $numbers, $low, $high, $find) { /** * notice1 循環退出條件 */ if ($low > $high) { return -1; } /** * notice2 mid計算*/ $mid = $low + (($high - $low) >> 1); if ($numbers[$mid] > $find) { //notice3 high值更新 return search($numbers, $low, $mid - 1, $find); } elseif ($numbers[$mid] < $find) { //notice4 low值更新 return search($numbers, $mid + 1, $high, $find); } else { return $mid; } } /** * 求數字的平方根,保留6位小數 * @param [type] $number */ function squareRoot($number) { if ($number < 0) { return -1; } elseif ($number < 1) { $min = $number; $max = 1; } else { $min = 1; $max = $number; } $mid = $min + ($max - $min) / 2; while (getDecimalPlaces($mid) < 6) { $square = $mid * $mid; if ($square > $number) { $max = $mid; } elseif ($square == $number) { return $mid; } else { $min = $mid; } $mid = $min + ($max - $min) / 2; } return $mid; } /** * 計算數字小數點後有幾位數字 * @param [type] $number */ function getDecimalPlaces($number) { $temp = explode(‘.‘, $number); return @strlen($temp[1]); } // 測試二分查找給定值 $numbers = [0, 1, 2, 3, 3, 4, 5, 6, 7, 9]; $find = 6; echo binarySearch($numbers, $find); echo "\n"; //測試求平方根 echo squareRoot(3); echo "\n";
<?php /** * 找到第一個=value的元素 * @param array $numbers */ function findFirstEqual(array $numbers, $find) { $length = count($numbers); $low = 0; $high = $length - 1; while ($low <= $high) { $mid = $low + (($high - $low) >> 1); if ($numbers[$mid] > $find) { $high = $mid - 1; } else if ($numbers[$mid] < $find) { $low = $mid + 1; } else { /** * 如果是第一個元素,或之前一個元素不等於我們要找的值 * 我們就找到了第一個=find的element */ if ($mid == 0 || $numbers[$mid - 1] != $find) { return $mid; } else { $high = $mid - 1; } } } return -1; } /** * 找到最後一個=find的元素 * @param array $numbers * @param [type] $find */ function findLastEqual(array $numbers, $find) { $length = count($numbers); $low = 0; $high = $length - 1; while ($low <= $high) { $mid = $low + (($high - $low) >> 1); if ($numbers[$mid] > $find) { $high = $mid - 1; } else if ($numbers[$mid] < $find) { $low = $mid + 1; } else { /** * 如果mid是最後一個元素的index * 或mid後一個元素!=我們要找的值 * 則找到了最後一個=find的value */ if ($mid == $length - 1 || $numbers[$mid + 1] != $find) { return $mid; } else { $low = $mid + 1; } } } return -1; } /** * 找到第一個大於等於find的元素 * @param array $numbers * @param [type] $find */ function findFirstGreaterEqual(array $numbers, $find) { $length = count($numbers); $low = 0; $high = $length - 1; while ($low <= $high) { $mid = $low + (($high - $low) >> 1); if ($numbers[$mid] >= $find) { if ($mid == 0 || $numbers[$mid - 1] < $find) { return $mid; } else { $high = $mid - 1; } } else { $low = $mid + 1; } } return -1; } /** * 找到最後一個小於等於find的元素 * @param array $numbers * @param [type] $find */ function findLastLessEqual(array $numbers, $find) { $length = count($numbers); $low = 0; $high = $length - 1; while ($low <= $high) { $mid = $low + (($high - $low) >> 1); if ($numbers[$mid] <= $find) { if ($mid == $length - 1 || $numbers[$mid + 1] > $find) { return $mid; } $low = $mid + 1; } else { $high = $mid - 1; } } return -1; } /** * 循環數組中找指定元素 * @param array $numbers * @param [type] $find * * @return void * @date 2018/11/27 * @author yuanliandu <[email protected]> */ function searchCircularArray(array $numbers, $find) { $length = count($numbers); $low = 0; $high = $length - 1; while ($low <= $high) { $mid = $low + (($high - $low) >> 1); if ($numbers[$mid] === $find) { return $mid; } if ($numbers[$low] > $numbers[$mid]) { // 後半部分是有序數組 if (($numbers[$mid] < $find) && ($numbers[$high] >= $find)) { if ($numbers[$high] === $find) return $high; //在後半個區間內 $low = $mid + 1; } else { $high = $mid - 1; } } else { // 前半部分是有序的 if (($numbers[$low] <= $find) && ($numbers[$mid] > $find)) { // 在有序區間內 if ($numbers[$low] === $find) return $low; $high = $mid - 1; } else { $low = $mid + 1; } } } return -1; } /*** * 測試 */ $numbers = [1, 2, 3, 3, 3, 4, 5, 6, 8, 11, 13]; $find = 3; var_dump(findFirstEqual($numbers, $find));//找到第一個等於find的元素,結果:2 var_dump(findFirstGreaterEqual($numbers, $find));//找到第一個大於等於find的元素,結果:2 var_dump(findLastEqual($numbers, $find));//找到最後一個=find的元素,結果:4 var_dump(findLastLessEqual($numbers, $find));//找到最後一個小於等於find的元素,結果:4 //測試在循環數組中找到指定數字 $numbers = [9, 10, 1, 2, 3, 4, 5, 6, 7, 8]; $find = 2; var_dump(searchCircularArray($numbers, $find)); //結果:3
算法筆記-二分查找