二分查找是一种常见的查找方式。在生活中有一个猜大小的例子。比如给定一个0-100的范围,让你猜出事先我所设置的数字,每次把数字的范围缩小到一半。第一次猜50,大了还是小了,继续缩小数字的范围。但是有一个前提,我们得保证我们查找的是一个有序的范围。
二分查找针对的是一个有序的集合。它的查找算法有点类型分治的思想,就像上面所说的。每次我通过中间的数和指定的数进行比较,判断大小,缩小猜测的区间,直到压缩到区间为1个数时或者不存在的情况,结果也就出来了。二分查找是一种高效的查找算法,它的时间复杂度是O(Log n).
1.我们先实现一个最基础的,在一个有序数组中(数组没有重复的值)查找给定值。(迭代)
function binarySerach($data,$res)
{
$l=0;
$r=count($data)-1;
while($l<=$r){
// $middle=floor(($l+$r)/2);
// $middle=$l+floor(($r-$l)/2);
$middle=$l+(($r-$l)>>1); //使用位运算查找更高效
if($data[$middle]==$res) return $middle;
elseif ($data[$middle]>$res) $r=$middle-1;
else $l=$middle+1;
}
return -1;
}
$data=[2,5,6,7,12,34];
$res=12;
var_dump(binarySerach($data,$res));
使用递归实现刚才的操作。
function binarySerach($data,$res){
return recursion($data,0,count($data)-1,$res);
}
function recursion($data,$l,$r,$res)
{
if($l>$r){
return -1;
}
$middle=$l+(($r-$l)>>1);
if($data[$middle]==$res) return $middle;
elseif ($data[$middle]>$res) return recursion($data,$l,$middle-1,$res);
else return recursion($data,$middle+1,$r,$res);
}
$data=[2,5,6,7,12,34];
$res=12;
var_dump(binarySerach($data,$res));
上面的那个注释是在数字没有重复的情况下,现在我们来实现数组中有重复值的情况下,如何查找出第一个等于给定值的元素。其实就是在做等于判断的时候如果索引是0那么是第一个等于给定值的数,或者当前等于给定值的上一个索引值不等于给定值。
function binarySerach($data,$res){
$l=0;
$r=count($data);
while($l<=$r){
$middle=$l+(($r-$l)>>1);
if($data[$middle]>$res) $r=$middle-1;
elseif($data[$middle]<$res) $l=$middle+1;
else{
if($middle==0 || $data[$middle-1] !==$res) return $middle;
else $r=$middle-1;
}
}
}
$data=[2,5,6,7,8,8,10];
$res=8;
var_dump(binarySerach($data,$res));
查找第一个大于等于给定值的元素。
//查找第一个大于等于给定值的数
function binarySerach($data,$res)
{
$l=0;
$r=count($data)-1;
while($l<=$r){
$middle=$l+(($r-$l)>>1);
if($data[$middle]<$res) $l=$middle+1;
else{
if($middle==0 || $data[$middle-1]<$res ) return $middle;
else $r=$middle-1;
}
}
}
$data=[2,5,6,7,8,8,10];
$res=9;
var_dump(binarySerach($data,$res));
针对数组是一个循环有序的数组Leetcode35题
function binarySerach($data,$res)
{
$l=0;
$r=count($data)-1;
while($l<=$r){
$middle=$l+(($r-$l)>>1);
if($data[$middle]==$res) return $middle;
elseif ($data[$middle]>$data[$r]){
if($data[$l]<=$res && $data[$middle]>$res) $r=$middle-1;
else $l=$middle+1;
}else{
if($data[$middle]<=$res && $data[$r] >$res) $r=$middle-1;
else $l=$middle+1;
}
}
}
$data=[5,6,7,8,1,2,3,4];
$res=7;
var_dump(binarySerach($data,$res));
当然二分查找还有很多的应用场景,我就总结到这了。