Java 二分查找代码详解
简介
二分查找(Binary Search)是一种在有序数组中查找特定元素的高效算法。相比于顺序查找需要遍历整个数组,二分查找每次迭代都能将搜索区间减半,大大提高了查找效率。在 Java 中,实现二分查找的代码有多种方式,本文将深入探讨其基础概念、使用方法、常见实践以及最佳实践。
目录
- 基础概念
- 使用方法
- 常见实践
- 最佳实践
- 小结
- 参考资料
基础概念
二分查找的核心思想是利用数组的有序性,通过将目标值与数组中间元素进行比较,逐步缩小搜索范围。如果目标值等于中间元素,则查找成功;如果目标值小于中间元素,则在左半部分继续查找;如果目标值大于中间元素,则在右半部分继续查找。这个过程不断重复,直到找到目标值或搜索区间为空。
使用方法
递归实现
public class BinarySearchRecursive {
public static int binarySearch(int[] arr, int target, int left, int right) {
if (left > right) {
return -1;
}
int mid = left + (right - left) / 2;
if (arr[mid] == target) {
return mid;
} else if (arr[mid] > target) {
return binarySearch(arr, target, left, mid - 1);
} else {
return binarySearch(arr, target, mid + 1, right);
}
}
public static void main(String[] args) {
int[] arr = {1, 3, 5, 7, 9, 11};
int target = 7;
int result = binarySearch(arr, target, 0, arr.length - 1);
if (result == -1) {
System.out.println("目标元素未找到");
} else {
System.out.println("目标元素在索引 " + result + " 处");
}
}
}
迭代实现
public class BinarySearchIterative {
public static int binarySearch(int[] arr, int target) {
int left = 0;
int right = arr.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (arr[mid] == target) {
return mid;
} else if (arr[mid] > target) {
right = mid - 1;
} else {
left = mid + 1;
}
}
return -1;
}
public static void main(String[] args) {
int[] arr = {1, 3, 5, 7, 9, 11};
int target = 7;
int result = binarySearch(arr, target);
if (result == -1) {
System.out.println("目标元素未找到");
} else {
System.out.println("目标元素在索引 " + result + " 处");
}
}
}
常见实践
查找第一个和最后一个出现的位置
有时候我们不仅需要找到目标元素,还需要知道它在数组中第一次和最后一次出现的位置。
public class BinarySearchFirstAndLast {
public static int[] searchRange(int[] nums, int target) {
int[] result = {-1, -1};
result[0] = findFirst(nums, target);
result[1] = findLast(nums, target);
return result;
}
private static int findFirst(int[] nums, int target) {
int left = 0;
int right = nums.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target) {
if (mid == 0 || nums[mid - 1] != target) {
return mid;
} else {
right = mid - 1;
}
} else if (nums[mid] > target) {
right = mid - 1;
} else {
left = mid + 1;
}
}
return -1;
}
private static int findLast(int[] nums, int target) {
int left = 0;
int right = nums.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target) {
if (mid == nums.length - 1 || nums[mid + 1] != target) {
return mid;
} else {
left = mid + 1;
}
} else if (nums[mid] > target) {
right = mid - 1;
} else {
left = mid + 1;
}
}
return -1;
}
public static void main(String[] args) {
int[] nums = {5, 7, 7, 8, 8, 10};
int target = 8;
int[] result = searchRange(nums, target);
System.out.println("第一个位置: " + result[0]);
System.out.println("最后一个位置: " + result[1]);
}
}
最佳实践
- 确保数组有序:二分查找的前提是数组必须有序。在进行二分查找之前,务必对数组进行排序。
- 处理边界情况:在代码中要仔细处理边界情况,如数组为空、目标值不存在等。
- 选择合适的实现方式:递归实现简洁但可能存在栈溢出问题,适用于较小规模的数组;迭代实现更高效,适用于大规模数组。
- 优化性能:在计算中间索引时,使用
left + (right - left) / 2
而不是(left + right) / 2
,可以避免left + right
可能导致的整数溢出。
小结
本文详细介绍了 Java 中二分查找的基础概念、使用方法、常见实践以及最佳实践。通过递归和迭代两种方式实现了基本的二分查找,并展示了如何查找目标元素的第一个和最后一个出现位置。在实际应用中,应根据具体情况选择合适的实现方式,并注意处理边界情况和优化性能,以充分发挥二分查找的优势。
参考资料
- 《Effective Java》
- Oracle Java 官方文档
- LeetCode 相关题目及讨论区