二分查找是一种算法,其输入是一个有序的元素列表(必须有序的原因稍后解释)。如果要查找的元素包含在列表中,二分查找返回其位置;否则返回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越来越大。由此可见二分查找的性能优势