二分法の問題: 順序付けされた配列 A で、配列内の要素の添字を見つけます (この問題は小さいものから大きいものへの順序で出題されます)

二分探索アルゴリズムとも呼ばれる二分探索アルゴリズムは、順序付けされた配列内の特定の要素を見つけるための効率的なアルゴリズムです。その基本的な考え方は、ターゲット要素が見つかるか、ターゲット要素が存在しないと判断されるまで、検索間隔を徐々に狭めることです。

アルゴリズムの手順は次のとおりです。

  1. 初期化: まず、配列の左右の境界を決定します。通常、最初は左の境界が配列の開始インデックスであり、右の境界が終了インデックスです。配列の。

  2. 中央の要素を検索する: 左右の境界の中央のインデックスを計算し、そのインデックスの要素値を取得します。

  3. 中間要素を比較:

    • 中央の要素がターゲット値と等しい場合、検索は成功し、要素インデックスが返されます。
    • 中央の要素がターゲット値よりも大きい場合は、ターゲット値が左半分にある必要があり、右境界が中央のインデックスの 1 つ左側に移動されることを意味します。
    • 中央の要素がターゲット値より小さい場合、ターゲット値が右半分にある必要があり、左側の境界が中央のインデックスの 1 つ右に移動されることを意味します。
  4. 繰り返し: 新しい検索間隔で、左側の境界が右側の境界より大きくなるまで手順 2 と 3 を繰り返します。この時点で、検索は失敗し、-1 が返されます。 、またはインジケーター要素が返されます。他の値は存在しません。

算法特点

  • 二分探索アルゴリズムの時間計算量は O(log n) です。ここで、n は配列のサイズです。これは、比較するたびに検索範囲が元のサイズの半分に縮小されるためです。

  • ただし、二分探索アルゴリズムでは、入力データが順序付けされている必要があります。配列に順序がない場合は、事前に並べ替える必要があります。

  • 二分検索は検索範囲を毎回半分に減らすため、特に大規模なデータ セットの場合に非常に効率的です。

  • 二分探索アルゴリズムは反復アルゴリズムであり、再帰的に実装することもできます。

Java バージョン:

package LeetCode_1.Binary_search;
//小淼的算法之路

//二分法题目:在有序数组中A内,查找数组中的某一个元素的下标(本题是从由小到大的顺序)


public class Binary_search {
    //二分查找算法版本1.0
    public static int BinarySearchBasic(int[] a, int target){
        int i = 0,j = a.length -1;//设置指针和初值
        while (i <= j){
            int m = (i + j)>>>1;//m:中间值
            if(target < a[m]){//若查找的在中间值左边(小于中间值),最大值指针j占据中间值-1的位置,在进行计算
                j = m -1;
            } else if (a[m] < target){//若查找的在中间值右边(大于中间值),最小值指针j占据中间值+1的位置,在进行计算
                i = m + 1;
            } else {
                return m;//否则就是target值与中间值相等,直接返回中间值
            }
        }
        return -1;//不存在时返回-1,因为能找到的都在数组当中,在数组中的都有一个索引值,所以能找到的输出的数组索引值不可能为-1
    }
    /*本题问题1:为什么i<=j 意味着区间未比较的元素,而不是i<j  ?
     *       答:因为i,j 它们指向的元素也会参与比较,若i<j,则参与比较的只能是i与j中间的值,若这时i与j指向的元素相同则该算法会发生错误。
     * 本题问题2:为什么int m = (i + j)>>>1;,而不是int m = (i + j) / 2;  ?
     *       答:如果使用int m = (i + j) / 2 来确定中间值的话多次循环会有问题:这与二进制的第一位是不是符号位有关(1:负,0:正)。
     *           然而int m = (i + j)>>>1 这种方式:将i+j表示成的二进制整体向右移动一位(二进制对应的十进制做/2操作)
     * */

    //二分查找算法版本2.0
    public static int BinarySearchUpgrades(int[] a, int target){
        int i = 0,j = a.length;         //第一处改动
        while (i < j){                  //第二处改动
            int m = (i + j)>>>1;
            if(target < a[m]){
                j = m;                  //第三处改动
            } else if (a[m] < target){
                i = m + 1;
            } else {
                return m;
            }
        }
        return -1;
    }

    //测试类
    public static void main(String[] args) {
        int[] a = {7,13,21,30,38,44,52,53,78,79,88,89,91,92,93,94};
        int target = 92;
        long startTime = System.nanoTime();;//开始时时间点
        int result = BinarySearchBasic(a, target);//执行的算法
        long endTime = System.nanoTime();//结束时时间点
        long elapsedTime = endTime - startTime;//算法占用时间
        if (result != -1) {
            System.out.println("二分查找法1.0版本----------"+"目标值 " + target + " 在数组中的索引是 " + result+"\n"+"算法执行时间(纳秒): " + elapsedTime);
        } else {
            System.out.println("二分查找法1.0版本----------"+"目标值 " + target + " 未在数组中找到");
        }
        long startTime_1 = System.nanoTime();;//开始时时间点
        int result_1 = BinarySearchUpgrades(a, target);
        long endTime_1 = System.nanoTime();//结束时时间点
        long elapsedTime_1 = endTime_1 - startTime_1;//算法占用时间
        if (result_1 != -1) {
            System.out.println("二分查找法2.0版本----------"+"目标值 " + target + " 在数组中的索引是 " + result_1+"\n"+"算法执行时间(纳秒): " + elapsedTime_1);
        } else {
            System.out.println("二分查找法2.0版本----------"+"目标值 " + target + " 未在数组中找到");
        }
    }
}


JavaScript:

function binarySearchBasic(a, target) {
    let i = 0, j = a.length - 1; // 设置指针和初值
    while (i <= j) {
        let m = (i + j) >>> 1; // m:中间值
        if (target < a[m]) {
            // 若查找的在中间值左边(小于中间值),最大值指针j占据中间值-1的位置,在进行计算
            j = m - 1;
        } else if (a[m] < target) {
            // 若查找的在中间值右边(大于中间值),最小值指针j占据中间值+1的位置,在进行计算
            i = m + 1;
        } else {
            return m; // 否则就是target值与中间值相等,直接返回中间值
        }
    }
    return -1; // 不存在时返回-1,因为能找到的都在数组当中,在数组中的都有一个索引值,所以能找到的输出的数组索引值不可能为-1
}

function binarySearchUpgrades(a, target) {
    let i = 0, j = a.length; // 第一处改动
    while (i < j) { // 第二处改动
        let m = (i + j) >>> 1;
        if (target < a[m]) {
            j = m; // 第三处改动
        } else if (a[m] < target) {
            i = m + 1;
        } else {
            return m;
        }
    }
    return -1;
}

const a = [7, 13, 21, 30, 38, 44, 52, 53, 78, 79, 88, 89, 91, 92, 93, 94];
const target = 92;

let startTime = performance.now(); // 开始时时间点
let result = binarySearchBasic(a, target);
let endTime = performance.now(); // 结束时时间点
let elapsedTime = endTime - startTime; // 算法占用时间

if (result !== -1) {
    console.log(`二分查找法1.0版本---------- 目标值 ${target} 在数组中的索引是 ${result}\n算法执行时间(毫秒): ${elapsedTime}`);
} else {
    console.log(`二分查找法1.0版本---------- 目标值 ${target} 未在数组中找到`);
}

let startTime1 = performance.now(); // 开始时时间点
let result1 = binarySearchUpgrades(a, target);
let endTime1 = performance.now(); // 结束时时间点
let elapsedTime1 = endTime1 - startTime1; // 算法占用时间

if (result1 !== -1) {
    console.log(`二分查找法2.0版本---------- 目标值 ${target} 在数组中的索引是 ${result1}\n算法执行时间(毫秒): ${elapsedTime1}`);
} else {
    console.log(`二分查找法2.0版本---------- 目标值 ${target} 未在数组中找到`);
}

おすすめ

転載: blog.csdn.net/lbcyllqj/article/details/134024820