乐趣区

PHP算法二分查找

二分查找

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

退出移动版