Binary Search 二元搜尋找到最接近的答案

Binary Search 二元搜尋找到最接近的答案

找出 大於等於答案(>= target) 的索引位置,最後回傳 左指標位置 left 就是要找的答案

程式範例

JavaScript

function BinarySearch(searchNumberArray, searchNumber) {
    // 左側指標
    var leftNumberPointer = 0;
    // 右側指標
    var rightNumberPointer = searchNumberArray.length - 1;
    while (leftNumberPointer <= rightNumberPointer) {
        // 中間指標
        var middleNumberPointer = Math.floor((rightNumberPointer + leftNumberPointer) / 2);
        // 中間指標數字
        var middleNumber = searchNumberArray[middleNumberPointer];
        if (searchNumber == middleNumber) {
            // 如果「要找的數字」與「中間指標數字」相同
            // 找到了,回傳這個數字指標位置
            return middleNumberPointer;
        }
        else if (searchNumber < middleNumber) {
            // 如果「要找的數字」小於「中間指標數字」
            // 表示「中間指標」右邊的所有數字都"大於"「要找的數字」
            // 所以將「右側指標」移動到目前「中間指標 - 1」的位置
            rightNumberPointer = middleNumberPointer - 1;
        }
        else {
            // 如果「要找的數字」大於「中間指標數字」
            // 表示「中間指標」左邊的所有數字都"小於"「要找的數字」
            // 所以將「左側指標」移動到目前「中間指標 + 1」的位置
            leftNumberPointer = middleNumberPointer + 1;
        }
    }

    // 如果都沒有找到,回傳最接近的指標
    return leftNumberPointer;
}

TypeScript

function BinarySearch(searchNumberArray: number[], searchNumber: number){
    // 左側指標
    let leftNumberPointer: number = 0;
    // 右側指標
    let rightNumberPointer: number = searchNumberArray.length - 1;

    while (leftNumberPointer <= rightNumberPointer) {
        // 中間指標
        let middleNumberPointer = Math.floor((rightNumberPointer + leftNumberPointer) / 2);
        // 中間指標數字
        let middleNumber = searchNumberArray[middleNumberPointer];
        if (searchNumber == middleNumber) {
            // 如果「要找的數字」與「中間指標數字」相同
            // 找到了,回傳這個數字指標位置
            return middleNumberPointer;
        } else if (searchNumber < middleNumber) {
            // 如果「要找的數字」小於「中間指標數字」
            // 表示「中間指標」右邊的所有數字都"大於"「要找的數字」
            // 所以將「右側指標」移動到目前「中間指標 - 1」的位置
            rightNumberPointer = middleNumberPointer - 1;
        } else {
            // 如果「要找的數字」大於「中間指標數字」
            // 表示「中間指標」左邊的所有數字都"小於"「要找的數字」
            // 所以將「左側指標」移動到目前「中間指標 + 1」的位置
            leftNumberPointer = middleNumberPointer + 1;
        }
    }

    // 如果都沒有找到,回傳最接近的指標
    return leftNumberPointer;
}

說明

leftright 代表著可能含有答案的閉區間,所以答案一定在這個範圍內

對任何一個數字,假如一直找不到,這個區間會不斷減小,直到走到 left == right ,此時區間內只剩下 1 個數字。

有可能最終大於等於、或小於我們要找的 target,最接近的答案表示沒有 等於,只有可能是 大於小於

最後的左右指標區間數值,大於要找的數字

最後左右指標數字 6 大於 要找的數字 5.5

索引 0 1 2 3 4 5 6 7 8 9
數字陣列 0 1 2 3 4 5 6 7 8 9
指標位置 左指標 == 右指標

如果大於 target,我們會讓 right = mid - 1,而 left 不變

left 繼續停留在我們想要的位置上

索引 0 1 2 3 4 5 6 7 8 9
數字陣列 0 1 2 3 4 5 6 7 8 9
指標位置 右指標 左指標

最後的左右指標區間數值,小於要找的數字

最後左右指標數字 6 小於 要找的數字 6.5

索引 0 1 2 3 4 5 6 7 8 9
數字陣列 0 1 2 3 4 5 6 7 8 9
指標位置 左指標 == 右指標

如果小於 target,我們會讓 left = mid + 1right 不變

剛好把 left 移到我們想要的位置上

索引 0 1 2 3 4 5 6 7 8 9
數字陣列 0 1 2 3 4 5 6 7 8 9
指標位置 右指標 左指標

最後的左右指標區間數值,小於要找的數字,數值比陣列大

最後左右指標數字 9 小於 要找的數字 99

索引 0 1 2 3 4 5 6 7 8 9
數字陣列 0 1 2 3 4 5 6 7 8 9
指標位置 左指標 == 右指標

如果小於 target,我們會讓 left = mid + 1right 不變

剛好把 left 移到我們想要的位置上

索引 0 1 2 3 4 5 6 7 8 9 10
數字陣列 0 1 2 3 4 5 6 7 8 9
指標位置 右指標 左指標

找出 大於等於答案(>= target) 的索引位置,而陣列中都沒有這個數字,所以 left 會超出陣列 1 格

最後的左右指標區間數值,大於要找的數字,數值比陣列小

最後左右指標數字 6 大於 要找的數字 -1

索引 0 1 2 3 4 5 6 7 8 9
數字陣列 0 1 2 3 4 5 6 7 8 9
指標位置 左指標 == 右指標

如果大於 target,我們會讓 right = mid - 1,而 left 不變

left 繼續停留在我們想要的位置上

索引 -1 0 1 2 3 4 5 6 7 8 9
數字陣列 0 1 2 3 4 5 6 7 8 9
指標位置 右指標 左指標

參考資料