二分查找
二分查找(Binary Search),也称为折半查找,是一种在有序数组中查找特定元素的高效搜索算法。它的核心思想是"分而治之",通过不断将搜索范围缩小一半,从而实现对数级的时间复杂度,使其在处理大规模数据时效率远超线性查找。
使用前提
- 数据结构必须有序:数组必须是升序或降序排列的。如果数据无序,需要先排序,但这会增加 O(n log n) 的时间开销。
- 支持随机访问:必须能通过索引在 O(1) 时间内访问任意位置的元素。因此,它非常适合数组,但不适合链表。
复杂度分析
- 时间复杂度:O(log n)
- 空间复杂度:O(1)
实现
java
public class BinarySearch {
/**
* 在有序数组中查找目标值
* @param nums 已排序的数组(升序)
* @param target 要查找的目标值
* @return 目标值的索引,如果不存在则返回 -1
*/
public static int binarySearch(int[] nums, int target) {
// 1. 初始化左右指针,定义搜索区间为闭区间 [left, right]
int left = 0;
int right = nums.length - 1;
// 2. 当搜索区间不为空时,持续查找
// 循环条件是 left <= right,因为当 left == right 时,区间内仍有一个元素需要检查
while (left <= right) {
// 3. 计算中间位置
// 使用 left + (right - left) / 2 而不是 (left + right) / 2,可以防止 (left + right) 过大时发生整数溢出
int mid = left + (right - left) / 2;
// 4. 比较中间元素与目标值
if (nums[mid] == target) {
// 找到目标值,返回其索引
return mid;
} else if (nums[mid] < target) {
// 目标值在右半区,更新左边界
// 因为 nums[mid] 已经被检查过且不等于 target,所以新的左边界是 mid + 1
left = mid + 1;
} else {
// 目标值在左半区,更新右边界
// 同理,新的右边界是 mid - 1
right = mid - 1;
}
}
// 5. 循环结束仍未找到,返回 -1
return -1;
}
public static void main(String[] args) {
int[] arr = {2, 4, 7, 10, 15, 18, 21};
int target = 15;
int result = binarySearch(arr, target);
System.out.println("目标值 " + target + " 的索引为: " + result); // 输出: 4
}
}
优缺点
优点
- 查找效率极高:O(log n) 的时间复杂度使其在处理大规模数据时优势巨大。
缺点
- 依赖有序数据:如果数据是无序的,需要先排序,这可能得不偿失。
- 不适用于频繁增删的数据:数组的插入和删除操作成本较高(O(n)),如果数据集需要频繁变动,维护其有序性的开销会很大。