This commit is contained in:
krahets
2023-05-21 19:07:34 +08:00
parent 7b05aed8f5
commit 0c64fc7315
2 changed files with 285 additions and 8 deletions
+7 -8
View File
@@ -4,7 +4,7 @@ comments: true
# 6.1.   二分查找
「二分查找 Binary Search」是一种基于分治思想的高效搜索算法。它利用数据的有序性,每轮减少一半搜索范围,实现定位目标元素
「二分查找 Binary Search」是一种基于分治思想的高效搜索算法。它利用数据的有序性,每轮减少一半搜索范围,直至找到目标元素或搜索区间为空为止
我们先来求解一个简单的二分查找问题。
@@ -22,7 +22,7 @@ comments: true
**若数组不包含目标元素,搜索区间最终会缩小为空**,即达到 $i > j$ 。此时,终止循环并返回 $-1$ 即可。
为了更清晰地表示区间,我们在下图中以折线图的形式表示数组。
如下图所示,为了更清晰地表示区间,我们以折线图的形式表示数组。
=== "<0>"
![二分查找步骤](binary_search.assets/binary_search_step0.png)
@@ -50,8 +50,6 @@ comments: true
值得注意的是,**当数组长度 $n$ 很大时,加法 $i + j$ 的结果可能会超出 `int` 类型的取值范围**。为了避免大数越界,我们通常采用公式 $m = \lfloor {i + (j - i) / 2} \rfloor$ 来计算中点。
有趣的是,理论上 Python 的数字可以无限大(取决于内存大小),因此无需考虑大数越界问题。
=== "Java"
```java title="binary_search.java"
@@ -105,6 +103,7 @@ comments: true
i, j = 0, len(nums) - 1
# 循环,当搜索区间为空时跳出(当 i > j 时为空)
while i <= j:
# 理论上 Python 的数字可以无限大(取决于内存大小),无需考虑大数越界问题
m = (i + j) // 2 # 计算中点索引 m
if nums[m] < target:
i = m + 1 # 此情况说明 target 在区间 [m+1, j] 中
@@ -533,12 +532,12 @@ comments: true
## 6.1.2. &nbsp; 优点与局限性
二分查找效率很高,主要体现在
二分查找在时间和空间方面都有较好的性能
- **二分查找的时间复杂度较低**。对数阶在大数据量情况下具有显著优势。例如,当数据大小 $n = 2^{20}$ 时,线性查找需要 $2^{20} = 1048576$ 轮循环,而二分查找仅需 $\log_2 2^{20} = 20$ 轮循环。
- **二分查找无需额外空间**。哈希查找相比,二分查找更加节省空间。
- **二分查找的时间效率高**。在大数据量下,对数阶的时间复杂度具有显著优势。例如,当数据大小 $n = 2^{20}$ 时,线性查找需要 $2^{20} = 1048576$ 轮循环,而二分查找仅需 $\log_2 2^{20} = 20$ 轮循环。
- **二分查找无需额外空间**。相较于需要借助额外空间的搜索算法(例如哈希查找,二分查找更加节省空间。
然而,并非所有情况下都可使用二分查找,原因如下:
然而,二分查找并非适用于所有情况,原因如下:
- **二分查找仅适用于有序数据**。若输入数据无序,为了使用二分查找而专门进行排序,得不偿失。因为排序算法的时间复杂度通常为 $O(n \log n)$ ,比线性查找和二分查找都更高。对于频繁插入元素的场景,为保持数组有序性,需要将元素插入到特定位置,时间复杂度为 $O(n)$ ,也是非常昂贵的。
- **二分查找仅适用于数组**。二分查找需要跳跃式(非连续地)访问元素,而在链表中执行跳跃式访问的效率较低,因此不适合应用在链表或基于链表实现的数据结构。