二分查找
二分查找也称折半查找(Binary Search),它是一种效率较高的查找方法。但是,折半查找要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列。
算法要求
1、必须采用顺序存储结构。
2、必须按关键字大小有序排列。
算法步骤
其实,二分查找也还是比较容易理解的,大概就是一分为二,然后两边比较,保留有效区间,继续一分为二查找,直到找到或者超出区间则结束,所以二分查找的基本步骤是:
1、确定要查找的区间
2、确定要二分时的参照点
3、区间内选取二分点
4、根据二分点的值,综合左右区间情况以及求解的目的,舍去一半无用的区间
5、继续在有效区间重复上面的步骤
代码示例
这里主要用非递归和递归两种实现方式查找,代码如下:
1、非递归查找
/*
* 二分查找(也叫折半查找)-- 非递归
* array $arr 待查找区间
* int $number 查找数
* int 返回找到的键
*/
public function binarySearch($arr,$number){
// 待查找的区间不为数组或为空,则返回 -1
if(!is_array($arr) || empty($arr)){return -1;}
sort($arr); // 二分查找关键点
$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;
}
}
return -1;
}
2、递归查找
/*
* 二分查找(也叫折半查找)-- 递归
* array $arr 待查找区间
* int $number 查找数
* int $lower 低点
* int $high 高点
*/
public function binarySearchRecursion($arr,$number,$lower,$high)
{
// 待查找区间如果不是数组或为空,返回 -1
if(!is_array($arr) || empty($arr)){return -1;}
sort($arr);
$len=count($arr);
$middle=intval(($lower+$high)/2);
if($arr[$middle]>$number){
// 查找数比参照值小,舍去右边
return $this->binarySearchRecursion($arr,$number,0,$middle-1);
}elseif($arr[$middle]<$number){
// 查找数比参照值大,舍去左边
return $this->binarySearchRecursion($arr,$number,$middle+1,$high);
}else{
// 查找数与参照值相等,则返回
return $middle;
}
// 找不到,则返回 -1
return -1;
}
算法使用
需求是在待查找区间 $arr 中,找出 $number 所在的位置,调用算法如下:
// 待查找区间的数组
$arr=array(1,2,3,4,5,6,7,10,12,14,18,16,20);
// 非递归查找 $arr 中 25 所在的位置
$binaryKey=$this->binarySearch($arr,25);
// 递归查找 $arr 中 12 所在位置
$binarySearchRecursionKey=$this->binarySearchRecursion($arr,1,12,count($arr)-1);
// 打印输出
print_r($binaryKey);
echo '//';
print_r($binarySearchRecursionKey);
输出结果
-1//8
时间复杂度分析
在有序数组中如果用暴力的算法去查找,也就是逐个遍历比较,那么时间复杂度是 O(n);但是,用二分查找后,因为每次可以舍去一半查找区间,所以会将时间复杂度减少到 O(logn),算法更优。(关于算法的时间复杂度与空间复杂度详细解释)
相关资料
PHP 算法之二分查找