1. 程式人生 > >修煉內功---資料結構與演算法15---二分法變形1

修煉內功---資料結構與演算法15---二分法變形1

除了正常的二分查詢,還有很多二分查詢的變形版本

符合標準的二分查詢條件的序列一般是比較理想的情況,如果要查詢的元素在序列中有多個怎麼辦?

在一個給定排序序列中查詢第一個等於給定值的元素

其實關鍵節點就在於在序列中找到值等於待查詢元素值時的處理

如果此時 $mid 位置已經到了序列的最左邊,不能再往左了,或者序列中索引小於 $mid 的上一個元素值不等於待查詢元素值,那麼此時 $mid 就是第一個等於待查詢元素值的位置,否則還要繼續往前找

<?php

/**
 * 二分查詢變形版:查詢第一個值等於給定值的元素(陣列中包含重複資料)
 */
function binary_search($nums, $num)
{
    if (count($nums) <= 1) return 0;

    return binary_search_internal($nums, $num, 0, count($nums) - 1);
}

function binary_search_internal($nums, $num, $low, $high)
{
    if ($low > $high) return -1;

    $mid = floor(($low + $high) / 2);

    if ($num < $nums[$mid]) {
        return binary_search_internal($nums, $num, $low, $mid - 1);
    } elseif ($num > $nums[$mid]) {
        return binary_search_internal($nums, $num, $mid + 1, $high);
    } else {
        if ($mid == 0 || $nums[$mid-1] != $num) {
            return $mid;
        } else {
            return binary_search_internal($nums, $num, $low, $mid - 1);
        }
    }
}

$nums = [1, 2, 3, 3, 4, 5, 6];
$index = binary_search($nums, 3);
print $index;

既然有第一個等於給定值的查詢,自然就有最後一個等於給定值的查詢

這就是二分查詢的第二個變形版本:在給定已排序序列中查詢最後一個等於給定值的元素

實現邏輯和上面類似,只需要改動 $num == $nums[$mid] 時的處理邏輯

只是這時的條件變成了 $mid 位置到了序列的最右邊,不能再往後了,或者索引大於 $mid 的後一個元素值不等於帶查詢元素,才返回 $mid,否則,還要繼續往後找

<?php

/**
 * 二分查詢變形版:查詢最後一個值等於給定值的元素(陣列中包含重複資料)
 */
function binary_search($nums, $num)
{
    if (count($nums) <= 1) return 0;

    return binary_search_internal($nums, $num, 0, count($nums) - 1);
}

function binary_search_internal($nums, $num, $low, $high)
{
    if ($low > $high) return -1;

    $mid = floor(($low + $high) / 2);

    if ($num < $nums[$mid]) {
        return binary_search_internal($nums, $num, $low, $mid - 1);
    } elseif ($num > $nums[$mid]) {
        return binary_search_internal($nums, $num, $mid + 1, $high);
    } else {
        if ($mid == count($nums) - 1 || $nums[$mid + 1] != $num) {
            return $mid;
        } else {
            return binary_search_internal($nums, $num, $mid + 1, $high);
        }
    }
}

$nums  = [1, 2, 3, 3, 4, 5, 6];
$index = binary_search($nums, 3);
print $index;