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在每次遞歸後都是不變的,每次遞歸變化的是查找區間,查找區間在縮小,直到鎖定最後中間值*/ 

原文來自:http://www.yigangwu.com/index.php?m=content&c=index&a=show&catid=28&id=35 
點擊打開鏈接

点赞