php关于二分查找的算法

在查找数据库的查询速度的时候看到了二分查找,然后就记录一下,一个不看不懂,看完后太简单的算法。
先说一下二分查找的概念:
二分查找又称折半查找,二分查找又称折半查找,优点是比较次数少,查找速度快,平均性能好;其缺点是要求待查表为有序表,且插入删除困难。因此,折半查找方法适用于不经常变动而查找频繁的有序列表。首先,假设表中元素是按升序排列,将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功;否则利用中间位置记录将表分成前、后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。【百度百科】


折半查找,顾名思义是一半一半的查找,先找中间项,中间项等于要查找的就直接返回,如果小于,那么就在当前中间项到最大值中找中间项对比,如果大于,就在最小值到中间项中找中间项对比,循环查找。

首先要知道二分查找的操作对象是一个有序表,就是排好序,比如要在100万条数据中查出一个想要的元素,普通查询平均会要查50万次,而二分查找最多需要查20次,看完原理就知道为什么二分查找怎么可能会需要这么少的次数。

 

/** 
 * @param $arr   待查询的有序表(有序数组) 
 * @param $needle  要查询的值 
 * @return float|int  成功返回值所在的key 不成功返回-1 
 *  
 * $low 数组key的查找范围最小值 
 * $top 数组key的查找范围最大值 
 *  
 */ 
function binary($arr,$needle){ 
    $low = 0;  
    $top = count($arr); 
    while($low <= $top){  //循环查找 
        $mid = floor(($low+$top)/2); //向下取整 
            //将数组折半,并将数组中间值与要查询的值做比较 
            if($arr[$mid]==$needle){  //如果中间值等于要查询的值,直接返回当前中间值的key 
                return $mid; 
            }elseif($arr[$mid]<$needle){ //如果中间值小于要查询的值,那么直接将中间值的key加1当作查询范围的最小值,参与下次循环 
                $low = $mid+1; 
            }else{ //如果中间值大于要查询的值,那么直接将中间值的key减1当作查询范围的最大值,参与下次循环 
                $top = $mid-1; 
            } 
        } 
    return -1;//查找不成功 
} 
$arr = array(1,2,3,4,5,9,23,44,55,56,77,89); 
echo binary($arr, 44); 
/*$arr的count()后的结果是$top=12,中间值的key是12/2 = 6; 
按照代码执行第一次循环会先比较$arr[6]和44,$arr[6] = 23;23<44,所以中间值的key加1当作查询范围的最小值,此时的$low=7,$top=12;此时中间值变为(7+12)/2 = 9(9.5的向下取整) 
继续第二次循环执行代码,比较$arr[9]和44,$arr[6] = 56;56>44,所以中间值的key减1当作查询范围的最大值,此时的$low = 7,$top=8(9-1),此时中间值变为(7+8)/2 = 7, 
继续第三次循环执行代码,比较$arr[7]和44,$arr[7] = 44;然后返回当前中间值的key 即:7。*/ 

 

 

以上就是一个简单的二分查找,看到一次一次的循环,而且每次循环的都是那三个逻辑,这里就会想到了递归:

 

 

/** 
 * @param $arr  要查找的有序数组 
 * @param $low  最小值 
 * @param $top  最大值 
 * @param $target  要查询的元素 
 * @return float|int  返回结果 
 */ 
function recursion($arr,$low,$top,$target){ 
    if($low<=$top){ 
        $mid = floor(($low+$top)/2); 
        if($arr[$mid]==$target){ 
            return $mid; 
        }elseif($arr[$mid]<$target){ 
            return recursion($arr,$mid+1,$top,$target); 
        }else{ 
            return recursion($arr,$low,$mid-1,$target); 
        } 
    }else{ 
        return -1; 
    } 
} 
$arr = array(1,2,3,4,5,9,23,44,55,56,77,89); 
echo recursion($arr,0,count($arr),44); 
/* $arr在每次递归后都是不变的,每次递归变化的是查找区间,查找区间在缩小,直到锁定最后中间值*/ 

 

 

你可能感兴趣的:(算法)