php关于二分查找的算法

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


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

首先要知道二分查找的操作对象是一个有序表,就是排好序,比如要在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在每次递归后都是不变的,每次递归变化的是查找区间,查找区间在缩小,直到锁定最后中间值*/ 


原文来自:http://www.yigangwu.com/index.php?m=content&c=index&a=show&catid=28&id=35 点击打开链接



原创粉丝点击