二分查找
二分查找也称折半查找(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算法之二分查找