Java 二分查找

2025年7月14日 | 阅读 7 分钟

二分查找是一种高效的算法,用于在已排序的数组或列表中搜索目标元素。它遵循分治法的思想。它比线性搜索更快。请注意,在执行二分查找之前,数组或列表必须已排序。如果我们有一个未排序的数组或列表,我们可以使用 Arrays.sort(arr) 方法对数组进行排序。

二分查找的工作原理

  1. 已排序数据要求:首先,检查给定的数组或列表是否按升序排序。如果未排序,则必须先进行排序。
  2. 查找中间元素:查找数组或列表的中间元素以比较目标值。
  3. 比较和缩小范围
    • 如果目标值与中间元素匹配,则找到其位置,搜索终止。
    • 如果目标值小于中间元素,则搜索在左侧子数组中继续。
    • 如果目标值大于中间元素,则搜索在右侧子数组中继续。
  4. 重复:在新的、缩小的搜索空间上重复步骤 2 和 3,直到找到目标值或搜索空间变为空(表示目标不存在)。

二分查找算法

二分查找示例

考虑以下数组。我们取了一个已排序的数组,我们要从中搜索值 28(目标元素)。

Binary Search Java

目标元素大于当前中间元素(即 28)。搜索移至右侧子数组。在右侧子数组中,中间元素是 32,目标元素(28)小于中间元素。因此,搜索移至数组的右侧。我们找到了目标元素。停止搜索。

Binary Search Java

二分查找的方法

执行二分查找有以下三种方法:

  1. 迭代方法
  2. 递归方法
  3. 使用 Arrays.binarySearch() 方法

二分查找示例

让我们在 Java 程序中实现二分查找逻辑。

示例

编译并运行

输出

Element found at index: 3

使用迭代方法进行二分查找

Java 中的二分查找迭代方法是一种直接而有效的技术,用于在已排序的数组中查找目标元素的位置。此方法使用 while 循环,在每次迭代后将搜索范围减半,并根据与目标值的比较来调整起始和结束索引。

示例

编译并运行

输出

Element found at index: 4

使用递归进行二分查找

递归方法在每次调用时将数组分成两半,根据与中间值比较的结果,将搜索区域缩小到左侧或右侧片段。递归继续进行,直到找到目标或搜索空间为空,此时算法终止。

让我们在 Java 程序中实现递归方法。

示例

编译并运行

输出

Element is found at index: 2

使用 Arrays.binarySearch() 方法进行二分查找

Java Arrays 类为 byte、char、int、float、double、long、object 和 short 数据类型提供了不同的 binarySearch() 方法变体。它是一个静态方法。

该方法使用二分查找算法搜索指定值。在此调用之前,数组必须已排序(通过 sort(int[]) 方法)。如果未排序,结果是不确定的。如果数组包含多个具有指定值的元素,则不保证找到哪个元素。

语法

该方法接受两个参数:要搜索的数组和要搜索的元素(键)。当找到目标元素时,它返回元素的索引值;否则,它返回一个负值,表示插入点以保持数组排序。

示例

编译并运行

输出

Element found at index: 4

使用 Collections.binarySearch() 方法进行二分查找

Java Collections 类还提供了内置的 binarySearch() 方法。该方法使用二分查找算法搜索指定的对象。列表必须按升序排序。如果列表未排序,结果是不确定的。如果列表包含多个与指定对象相等的元素,则不保证找到哪个元素。它通过提供标准化的优化方法来查找元素,从而简化了 Java Collections 中的搜索操作。

语法

该方法接受两个参数:要搜索的列表和要搜索的键元素。它返回键元素的索引值。

示例

编译并运行

输出

Element found at index: 5

复杂度分析

时间复杂度

在二分查找中,在每一步,算法都会将数组除以 2。经过 k 步后,大小变为 n / 2k。当我们解 n / 2k = 1 时,我们得到 k = log₂(n)。

情况复杂度描述
最佳O(1)在第一次比较时,元素位于中间索引处。
平均数O(log n)搜索空间在每一步都会减半,导致对数级别的比较。
最坏O(log n)元素位于末端之一或不存在,需要完整的 log(n) 步。

空间复杂度

方法复杂度描述
迭代O(1)为指针(low、high、mid)使用恒定空间。
递归O(log n)每次递归调用都会向调用堆栈添加一个新帧。

Java 二分查找选择题

1. 二分查找要正确处理数组,必须满足什么条件?

  1. 数组必须是未排序的。
  2. 数组必须按升序排序。
  3. 数组必须按降序排序。
  4. 数组可以按任何顺序。
 

答案:B)

解释:二分查找通过将搜索区间减半来工作,这只有在数组已排序时才可能。


2.二分查找的平均时间复杂度是多少?

  1. O(n)
  2. O(log n)
  3. O(n log n)
  4. O(1)
 

答案:B

解释:二分查找的平均情况复杂度为 O(log n),因为它在每次迭代中将搜索空间减半。


3.与线性搜索相比,在什么情况下二分查找会更有效?

  1. 大型未排序数组
  2. 大型已排序数组
  3. 小型未排序数组
  4. 小型已排序数组
 

答案:B)

解释:由于其对数时间复杂度,二分查找对于大型已排序数组更有效,而线性搜索的时间复杂度为 O(n)。


4.如果找不到目标元素,二分查找的返回值将是什么?

  1. -1
  2. 0
  3. 它应该被插入的索引
  4. 未定义行为
 

答案:A)

解释:在大多数实现中,二分查找返回 -1 来表示未找到目标元素。


5.以下关于二分查找的迭代和递归实现,哪项是正确的?

  1. 两者具有不同的时间复杂度。
  2. 递归实现由于调用堆栈而使用更多空间。
  3. 迭代实现由于循环而使用更多空间。
  4. 两者具有不同的时间和空间复杂度。
 

答案:B)

解释:虽然这两种实现都具有相同的时间复杂度,但递归实现为调用堆栈使用了额外的空间。


下一个主题Java 程序