二分查找(Binary Search),也称为折半查找,是一种高效的查找算法,适用于已排序的数组。其基本原理是通过不断缩小搜索范围来提高查找效率。具体步骤如下:
- 「假设数组已按升序或降序排列」:这是二分查找的前提条件。
- 「通过比较待查找元素与中间元素,确定元素所在的位置」:首先找到数组的中间元素,然后将待查找元素与中间元素进行比较。
- 「如果待查找元素大于中间元素,则在右半部分继续查找;如果小于中间元素,则在左半部分继续查找」:根据比较结果,将搜索范围缩小到数组的一半。
- 「重复上述步骤,直到找到目标元素或搜索范围为空」:如果找到了目标元素,则返回其索引;如果搜索范围为空,则表示目标元素不存在于数组中,返回-1。
下面,我们将通过具体的Java代码示例来详细说明二分查找算法的实现。
示例代码
package com.shiguozhan.day2;
import java.util.Arrays;
import java.util.Scanner;
public class work4 {
public static void main(String[] args) {
// 自己随机定义一个数组
int[] arr = {45, 86, 78, 32, 14, 71, 20, 7, 3, 5};
// 对数组进行排序
Arrays.sort(arr);
// 输出排序后的数组
System.out.println(Arrays.toString(arr));
// 创建Scanner对象,用于从控制台读取用户输入
Scanner sc = new Scanner(System.in);
System.out.println("请输入目标数字:");
// 读取用户输入的目标数字
int data = sc.nextInt();
// 调用binarySer方法,查找目标数字在数组中的位置
System.out.println("对应的位置为:" + binarySer(arr, data));
}
// 定义一个方法来实现查找
public static int binarySer(int[] arr, int number) {
// 定义两个变量来查找的范围
int min = 0;
int max = arr.length - 1;
// 使用循环不断的去找要查找的数据
while (true) {
// 如果min大于max,表示搜索范围为空,返回-1
if (min > max) {
return -1;
}
// 查找min和max的中间位置
int mid = (min + max) / 2;
// 拿min指向的元素跟查找的元素进行比较
if (arr[mid] > number) {
// number在mid的左边,更新max
max = mid - 1;
} else if (arr[mid] < number) {
// number在mid右边,更新min
min = mid + 1;
} else {
// number跟mid指向的元素一样,找到了
return mid;
}
}
}
}
代码解释
- 「数组定义与排序」:
int[] arr = {45, 86, 78, 32, 14, 71, 20, 7, 3, 5};
Arrays.sort(arr);
首先定义了一个包含10个整数的数组,并使用Arrays.sort()
方法对其进行升序排序。
- 「用户输入」:
Scanner sc = new Scanner(System.in);
System.out.println("请输入目标数字:");
int data = sc.nextInt();
使用Scanner
类从控制台读取用户输入的目标数字。
- 「二分查找方法」:
public static int binarySer(int[] arr, int number) {
int min = 0;
int max = arr.length - 1;
while (true) {
if (min > max) {
return -1;
}
int mid = (min + max) / 2;
if (arr[mid] > number) {
max = mid - 1;
} else if (arr[mid] < number) {
min = mid + 1;
} else {
return mid;
}
}
}
- 「初始化」:定义两个变量
min
和max
,分别表示当前搜索范围的起始和结束索引。 - 「循环查找」:使用
while(true)
循环不断缩小搜索范围,直到找到目标元素或搜索范围为空。 - 「计算中间位置」:
int mid = (min + max) / 2;
- 「比较中间元素」:
- 如果
arr[mid] > number
,则目标元素在左半部分,更新max = mid - 1
。 - 如果
arr[mid] < number
,则目标元素在右半部分,更新min = mid + 1
。 - 如果
arr[mid] == number
,则找到了目标元素,返回其索引mid
。 - 「返回结果」:如果
min > max
,表示搜索范围为空,返回-1表示未找到目标元素。
运行结果
假设用户输入的目标数字为71
,程序的运行结果如下:
[3, 5, 7, 20, 32, 45, 71, 78, 86]
请输入目标数字:
71
对应的位置为:6
这表明目标数字71
在排序后的数组中的索引为6
。
注意事项
- 「数组必须有序」:二分查找的前提条件是数组必须是有序的。如果数组未排序,需要先对其进行排序。
- 「时间复杂度」:二分查找的时间复杂度为O(log n),其中n是数组的长度。这使得二分查找在处理大型数据集时非常高效。
- 「空间复杂度」:二分查找的空间复杂度为O(1),因为它只使用了常数级别的额外空间。
其他实现方式
除了上述的迭代实现方式,二分查找还可以通过递归的方式实现。以下是递归实现的示例代码:
public class BinarySearchRecursive {
public static void main(String[] args) {
int[] arr = {3, 5, 7, 20, 32, 45, 71, 78, 86};
int target = 71;
int result = binarySearch(arr, target, 0, arr.length - 1);
if (result == -1) {
System.out.println("元素不在数组中");
} else {
System.out.println("元素在数组中的索引为: " + result);
}
}
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, mid + 1, right);
} else {
return binarySearch(arr, target, left, mid - 1);
}
}
}
递归实现解释
- 「递归方法定义」:
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, mid + 1, right);
} else {
return binarySearch(arr, target, left, mid - 1);
}
}
- 「基准条件」:如果
left > right
,表示搜索范围为空,返回-1。 - 「计算中间位置」:
int mid = left + (right - left) / 2;
- 「比较中间元素」:
- 如果
arr[mid] == target
,则找到了目标元素,返回其索引mid
。 - 如果
arr[mid] < target
,则目标元素在右半部分,递归调用binarySearch(arr, target, mid + 1, right)
。 - 如果
arr[mid] > target
,则目标元素在左半部分,递归调用binarySearch(arr, target, left, mid - 1)
。
通过上述两种实现方式,我们可以看到二分查找算法的高效性和简洁性。无论是迭代还是递归实现,都能有效地在有序数组中查找目标元素。