二分查找
最近学习了二分查找算法,总结归纳一下。
二分查找算法,也叫做折半查找算法。
下面来说明一下查找的流程:
数字是从1~99的范围,比如要查找23数字。
查找次数 | 查找范围 | 中间值 | 判断条件 |
第一次 | 0~99 | 49 | 49>23 |
第二次 | 0~48 | 24 | 24>23 |
第三次 | 0~23 | 11 | 11<23 |
第四次 | 12~23 | 17 | 17<23 |
第五次 | 18~23 | 20 | 20<23 |
第六次 | 21~23 | 22 | 22<23 |
第七次 | 23 | == | ✅ |
经过7次比较,得到最终等于target值得数字。
这个比较得过程就是运用得二分比较得思想,每次都与区间得中间值进行比较大小,根据值得大小情况进行缩小区间范围。
L为最小值
H为最大值(也就是数组得长度减1)
mid为中间值,中间值得计算如下采用了位运算mid = L + (H - L)>>1;
二分查找主要针对得是一个有序得数组集合,每次查找根据target值进行缩小范围查找,如果不是有序得,无法判断数据所在区间。
下面总结一下在写代码过程中容易出错得地方:
1、循环退出得条件
L <= H 而不是 L< H
2、mid取值问题
有多种写法,我们去例子俩种做一个比较把
第一种: mid = (L + H) /2; 还要运用取整函数进行取整,如果L 和 H 这个数据比较大的话,两者之和可能会溢出
第二种:采用位运算计算要比除法运算快的多。 mid = (L + (H - L) >>2); 向右挪一个位置,实际上就是做了一个除2的操作。
3、L 和 H值进行更新的问题
当 中间值 < target值时,将L挪到 mid +1位置,比较区间为 [mid+1,H]
当中间值 > target 值时,将H 挪到mid-1位置,比较区间为 [L,mid-1]
相等时即为target值 结束循环
以下二分查找的代码:(代码语言为php语言实现的)
1、二分查找target值题代码如下:
$arr = [1, 2, 3, 4, 6, 7, 9]; $target = 8; function ef($arr, $target, $l, $r) { while ($l <= $r) { $mid = $l + (($r - $l) >> 1); if ($arr[$mid] > $target) { $r = $mid - 1; } elseif ($arr[$mid] < $target) { $l = $mid + 1; } else { return 1; } } return -1; } $a = ef($arr, $target, 0, 7);
2、二分查找扩展题 -- 查找target值第一次出现的位置,会有重复的数据出现
$arr = [1, 2, 3, 4, 6, 7, 9, 9, 9, 9]; $target = 9; function fristTarget($arr, $target) { $n = count($arr); $l = 0; $r = $n - 1; while ($l <= $r) { $mid = $l + (($r - $l) >> 1); if ($arr[$mid] < $target) { $l = $mid + 1; } elseif ($arr[$mid] > $target) { $r = $mid - 1; } elseif ($arr[$mid] == $target) { if ($mid == $r) { return $mid; } if ($arr[$mid - 1] == $target) { $r = $mid - 1; } else { return $mid; } } } return -1; } $a = fristTarget($arr, 9);
3、二分查找扩展题-- 查找target值 最后一次出现的位置,会有重复的数据出现
$arr = [1, 2, 3, 4, 6, 7, 9, 9, 9, 0]; $target = 9; function endTarget($arr, $target) { $n = count($arr); $l = 0; $r = $n - 1; while ($l <= $r) { $mid = $l + (($r - $l) >> 1); if ($arr[$mid] > $target) { $r = $mid - 1; } elseif ($arr[$mid] < $target) { $l = $mid + 1; } else { if ($mid == $n - 1) { return $mid; } if ($arr[$mid + 1] == $target) { $l = $mid + 1; }else{ return $mid; } } } } $a = endTarget($arr,9);