二分查找法
二分查找算法,也称折半搜索算法,是一种在有序数组中查找某一特定元素的搜索算法。算法思想是不断的缩小查找范围。
思路步骤
1️⃣ 确定基准:
- 选定数组的中间元素(基准值)。
- 如果数组大小为偶数,通常选择中间的 右侧元素(也可以选择左侧元素,但不影响算法效果)。
2️⃣ 分割数组:
- 将数组分成两半,基准元素作为分割点。
- 对比目标值与基准值:
3️⃣ 判断目标位置:
- 如果目标值 小于基准值,则目标值一定在数组的 左半部分,下一轮查找范围是左半部分。
- 如果目标值 大于基准值,则目标值一定在数组的 右半部分,下一轮查找范围是右半部分。
4️⃣ 重复步骤:
- 在新的查找范围内,重新计算中间元素,并继续比较,逐步缩小查找范围,直到找到目标值或范围为空(即left > right)。

相比普通的顺序查找,除了数据量很少的情况下,二分查找会比顺序查找更快,对比图如下:

边界条件
是否包含中间元素?
当我们确定 arr[mid] 不是目标值时,我们需要缩小搜索范围。如果 mid 已经被检查过,再把它包含进去是没有意义的,所以:
-
如果目标值 比
arr[mid]大,那么mid及其左侧部分就不可能是目标值,所以我们 从mid + 1开始继续查找,即left = mid + 1。 -
如果目标值 比
arr[mid]小,那么mid及其右侧部分就不可能是目标值,所以我们 从mid - 1开始继续查找,即right = mid - 1。
循环终止条件?
当指针重合时,此时数组中还剩一个元素,该元素依然需要跟target比较。
代码实现
非递归版本(推荐):
1 function binarySearch(arr, target) { 2 let left = 0, right = arr.length - 1; 3 4 while (left <= right) { 5 let mid = Math.floor((left + right) / 2); 6 7 if (arr[mid] === target) { 8 return mid; // 找到目标值,返回索引 9 } else if (arr[mid] < target) { 10 left = mid + 1; // 目标值在右侧 11 } else { 12 right = mid - 1; // 目标值在左侧 13 } 14 } 15 16 return -1; // 没找到返回 -1 17 } 18 19 // 示例测试 20 let nums = [1, 2, 3, 4, 5, 6, 7, 8, 9]; 21 console.log(binarySearch(nums, 5)); // 输出: 4 22 console.log(binarySearch(nums, 10)); // 输出: -1(未找到)
递归版本:
function binarySearch(arr,start,end,target){ if(start > end){ return -1; } let mid = Math.floor((end-start)/2) if(arr[mid] === target){ return mid; }else if(arr[mid] < target ){ //右侧查找 return binarySearch(arr,mid + 1,end,target) }else{ //左侧查找 return binarySearch(arr,start,mid - 1,target) } }
如果数组中存在重复项,而我们需要找出第一个匹配项或最后一个匹配项,实现代码如下:
function binarySearch(arr, l, r, target, findBoundary = 'first') { if (start > end) { return -1; // 未找到目标元素 } let mid = start + Math.floor((end - start) / 2); //找到时,进一步查找(第1个还是最后一个) if (arr[mid] === target) { if (findBoundary === 'first') { // 如果是查找第1个,继续向左查找,直到找到第一个匹配项 if (mid === 0 || arr[mid - 1] !== target) { return mid; // 找到第一个匹配项 } return binarySearch(arr, start, mid - 1, target, findBoundary); } else if (findBoundary === 'last') { // 如果是查找最后一个,继续向右查找,直到找到最后一个匹配项 if (mid === end || arr[mid + 1] !== target) { return mid; // 找到最后一个匹配项 } return binarySearch(arr, mid + 1, end, target, findBoundary); } } else if (arr[mid] < target) { return binarySearch(arr, mid + 1, end, target, findBoundary); // 向右查找 } else { return binarySearch(arr, start, mid - 1, target, findBoundary); // 向左查找 } }

浙公网安备 33010602011771号