二分查找

218 阅读2分钟

二分查找是一种算法,其输入是一个有序的元素列表(必须有序的原因稍后解释)。如果要查找的元素包含在列表中,二分查找返回其位置;否则返回null。

示例

一个数组中包含着0,1,2,3......100的有序数组,查找值为55的索引

简单查找

遍历数组,从索引0开始一项一项的检查值是否为55

const simpleSearch = (arr, num) => {
    const len = arr.length; 
    for(let i = 0; i < len; i++) {
        if (arr[i] === num) {
            return i;
        }
    }
};
console.log(simpleSearch(arr, 55)); // 55,for循环遍历56次

检查值为55的索引,需要for循环56次,检查值为99的索引,需要循环100次

二分查找

判断索引在中间的值,如果等于要查找的值则返回,大了则可以排除大于该索引的值,小了也可以排除小于该索引的值,不管大于还是小于范围查找范围都会缩小一半。然后继续在缩小的范围内按照上面的方法循环查找,每次都会缩小一半的范围,直到查找到该值的索引。

const binarySearch = (arr, num) => {
    let low = 0; 
    let high = arr.length - 1; // low和high为数组的查找范围 
    while(low <= high) {
        const mid = Math.floor((low + high) / 2); // 从中间位置开始查找
        const guess = arr[mid];
        console.log(mid) // 50,75,62,56,53,54,55
        if (guess === num) {
            return mid;
        } else if (guess < num) { // 猜的值小了,则将查找范围的最小值改为猜得值的索引加1
            low = mid + 1;
        } else {
            high = mid - 1;      // 猜的值大了,则将查找范围的最大值改为猜得值的索引减1
        }
    }
    return null;
};
console.log(binarySearch(arr, 55)); // 55, 循环7次[0,100],[51,100],[51,74],[51,61],[51,55][54,55][55,55]

可以发现二分查找每次都将范围缩小一半,所以要查找n个数字,最多需要logn/log2次。

二分查找的优势

假设你要在字典中查找一个单词,而该字典包含240 000个单词,你认为每种查找最多需要多少步?

如果要查找的单词位于字典末尾,使用简单查找将需要240 000步。使用二分查找时,每次排除一半单词,直到最后只剩下一个单词。因此,使用二分查找只需18步。

一般而言,对于包含n个元素的列表,用二分查找最多需要logn/log2步,而简单查找最多需要n步。

算法的速度一般是指随着输入的增加,其运行时间将以什么样的速度增加。n的运行时间的增速相对于logn越来越大。由此可见二分查找的性能优势