搜索算法是解决问题的基础工具之一,而在众多搜索算法中,二分查找(Binary Search)凭借其惊人的效率脱颖而出——它能在对数时间复杂度(O(log n))内定位目标,尤其适用于有序数据集的高效检索。从数据库索引到编程框架的底层实现,二分查找的身影无处不在。
然而,这一看似简单的算法却暗藏玄机:边界的处理、循环终止条件的设定、重复元素的特殊场景……稍有不慎便会陷入“死循环”或“漏查”的陷阱。本文将深入剖析二分查找的核心思想,文末对应 leetcode 习题助你彻底掌握这一“高效搜索利器”!
目录
一、算法简介
二分查找(Binary Search)是一种在有序数组中快速定位目标元素的高效搜索算法,其核心思想是每次将搜索范围缩小一半。
二、算法执行过程
基于分治思想(Divide and Conquer),算法通过三个关键步骤实现高速搜索:
-
区间划分:确定当前搜索区间的中间位置
-
比较决策:将中间元素与目标值进行对比
-
范围收缩:根据比较结果排除不可能的半边区间
如同查字典时快速翻到目标字母区域的过程,二分查找每次操作都能排除约一半的无效数据。
三、算法原理
1.初始化指针
设置左指针 left = 0 和 右指针 right = size - 1
说明:数组下标从0开始,所以在计算出 数组元素个数 的基础上 right 再 -1,定义搜索区间为闭区间 [ left , right ]
2.循环查找
计算中间索引:
1.传统写法:
适用于规模较小(数组元素较少)时:int mid = ( left + rigth ) / 2
2.改进写法:
适用于规模较大(数组元素较多)时:int mid = left + (right - left) / 2
当数组非常大时,这时 left + right 可能会超过 int 的最大值,为了避免(left+right) 可能的整数溢出(整形只能储存四个字节数据),采用这种写法
3.比较目标值 key 与中间元素:
key < arr[mid]:要查找的值不在 mid 右边,调整右边界 right = mid-1
key > arr[mid]:要查找的值不在 mid 左边,调整左边界 left = mid+1
key = arr[mid]:说明找到了,直接返回 mid
4.中止条件
当 left > right 时,数组查找完毕,元素不存在,返回 -1
四、完整实现代码
#include <stdio.h>
int binary_search(int* arr, int key, int size)
{
//初始化双指针
int left = 0;
int right = size - 1;
while (left <= right) // 有效的搜索区间
{
//计算中间位置
int mid=(left+rigth)/2; // 适用于规模较小时
//int mid = left + (right - left)/2; // 规模较大时,避免整数溢出
if (key < arr[mid])
{
right = mid - 1;// 收缩右边界
}
else if (key > arr[mid])
{
left = mid + 1;// 收缩左边界
}
else
{
return mid;
}
}
return -1; // 未找到返回-1
}
int main()
{
int arr[] = {1,2,3,4,5,6,7,8,9,10};
int key = 7;
int len = sizeof(arr)/sizeof(arr[0]);
int index = binary_search(arr, key, len);
printf("元素 %d 的索引位置是:%d\n", key, index);
return 0;
}
五、关键点解析
-
前置条件:数组必须有序排列(升序或降序)
-
边界处理:闭区间查找需包含 left == right 的情况
-
中间值计算 ( 预防溢出 ) :推荐 left + (right - left) / 2
-
未找到情况处理:循环结束后返回 -1
-
循环条件:使用使用 while ( left <= right ) 确保最后一次比较的有效性
-
指针移动:
-
找到中间元素后立即排除已检查区域
-
每次循环至少排除一半元素
-
-
时间复杂度:
最优情况 | 平均情况 | 最坏情况 |
O(1) (首次mid即命中) | O(log n) | O(log n) |
注:每次迭代都将问题规模n减半,经过log₂n次操作后必然终止。
其时间复杂度为O(log n),相比线性查找的O(n)具有显著性能优势,比线性查找快指数级
8 . 空间复杂度:
仅需常数级别的额外空间存储指针变量,空间复杂度为O(1)。
六、性能对比
测试数据规模 | 线性查找 | 二分查找 |
---|---|---|
100万元素 | 500ms | <1ms |
10亿元素 | 不可行 | 30次循环内完成 |
八、LeetCode练习题
二分查找通过不断缩小搜索区间实现高效查找,核心在于正确处理边界条件和中间值计算。掌握该算法不仅能够提升编码能力,更是培养分治思维的重要实践。建议结合LeetCode题目进行强化训练,加深对算法细节的理解。
-
704. 二分查找(基础实现)
-
35. 搜索插入位置(边界处理)