3-1 二分搜索与线性搜索(对已排序列表)
二分搜索与线性搜索(对已排序列表)
在已排序的列表中查找一个目标元素,有两种经典方法:
- 线性搜索(Linear Search):从左到右逐个扫描每个元素,直到找到目标或遍历完整个列表。时间复杂度为 O(n)。
- 二分搜索(Binary Search):利用"分治法(Divide and Conquer)"的思想,每次将搜索范围缩小一半,时间复杂度为 O(log n)。但要求数据必须已排序。
以已排序数组 [1, 3, 5, 7, 9, 11, 13] 为例,查找目标值 7,二分搜索的过程如下:
数组: [1, 3, 5, 7, 9, 11, 13]
索引: 0 1 2 3 4 5 6
第1步: low=0, high=6, mid=3 → arr[3]=7 == 目标7,找到!
[1, 3, 5, 7, 9, 11, 13]
^
mid
仅需 1 次比较即可定位目标,而线性搜索需要 4 次。
对于更大的数组,二分搜索的优势更加明显。例如在 1000 个元素的数组中查找,线性搜索最多需要 1000 次比较,而二分搜索最多只需要 10 次。
线性搜索
线性搜索是最简单的搜索算法:从数组的第一个元素开始,依次与目标值比较,直到找到匹配的元素或遍历完整个数组。
基本思路:
- 从索引 0 开始,逐一比较每个元素与目标值。
- 如果找到匹配项,返回该索引。
- 如果遍历完整个数组仍未找到,返回 -1 表示未找到。
C++ 实现
#include <iostream>
// linear search: scan each element sequentially
int linearSearch(int arr[], int n, int target)
{
for (int i = 0; i < n; i++)
{
if (arr[i] == target)
{
return i; // found at index i
}
}
return -1; // not found
}
int main()
{
int arr[] = {2, 4, 6, 8, 10, 12, 14, 16, 18, 20};
int n = sizeof(arr) / sizeof(arr[0]);
// search for existing element
int target1 = 14;
int result1 = linearSearch(arr, n, target1);
if (result1 != -1)
{
std::cout << "Found " << target1 << " at index " << result1 << "\n";
}
else
{
std::cout << target1 << " not found in the array\n";
}
// search for non-existing element
int target2 = 15;
int result2 = linearSearch(arr, n, target2);
if (result2 != -1)
{
std::cout << "Found " << target2 << " at index " << result2 << "\n";
}
else
{
std::cout << target2 << " not found in the array\n";
}
return 0;
}
运行该程序将输出
Found 14 at index 6
15 not found in the array
C 实现
#include <stdio.h>
// linear search: scan each element sequentially
int linearSearch(int arr[], int n, int target)
{
for (int i = 0; i < n; i++)
{
if (arr[i] == target)
{
return i; // found at index i
}
}
return -1; // not found
}
int main()
{
int arr[] = {2, 4, 6, 8, 10, 12, 14, 16, 18, 20};
int n = sizeof(arr) / sizeof(arr[0]);
// search for existing element
int target1 = 14;
int result1 = linearSearch(arr, n, target1);
if (result1 != -1)
{
printf("Found %d at index %d\n", target1, result1);
}
else
{
printf("%d not found in the array\n", target1);
}
// search for non-existing element
int target2 = 15;
int result2 = linearSearch(arr, n, target2);
if (result2 != -1)
{
printf("Found %d at index %d\n", target2, result2);
}
else
{
printf("%d not found in the array\n", target2);
}
return 0;
}
运行该程序将输出
Found 14 at index 6
15 not found in the array
Python 实现
def linear_search(arr, target):
"""Linear search: scan each element sequentially."""
for i in range(len(arr)):
if arr[i] == target:
return i # found at index i
return -1 # not found
arr = [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
# search for existing element
target1 = 14
result1 = linear_search(arr, target1)
if result1 != -1:
print(f"Found {target1} at index {result1}")
else:
print(f"{target1} not found in the array")
# search for non-existing element
target2 = 15
result2 = linear_search(arr, target2)
if result2 != -1:
print(f"Found {target2} at index {result2}")
else:
print(f"{target2} not found in the array")
运行该程序将输出
Found 14 at index 6
15 not found in the array
Go 实现
package main
import "fmt"
// linear search: scan each element sequentially
func linearSearch(arr []int, target int) int {
for i := 0; i < len(arr); i++ {
if arr[i] == target {
return i // found at index i
}
}
return -1 // not found
}
func main() {
arr := []int{2, 4, 6, 8, 10, 12, 14, 16, 18, 20}
// search for existing element
target1 := 14
result1 := linearSearch(arr, target1)
if result1 != -1 {
fmt.Printf("Found %d at index %d\n", target1, result1)
} else {
fmt.Printf("%d not found in the array\n", target1)
}
// search for non-existing element
target2 := 15
result2 := linearSearch(arr, target2)
if result2 != -1 {
fmt.Printf("Found %d at index %d\n", target2, result2)
} else {
fmt.Printf("%d not found in the array\n", target2)
}
}
运行该程序将输出
Found 14 at index 6
15 not found in the array
Go 版本使用切片(slice)作为数组参数,线性搜索逻辑与 C++/Python 版本完全一致:从索引 0 开始逐个比较,找到返回索引,遍历完毕未找到则返回 -1。
查找目标 14 时,函数从索引 0 开始依次比较,经过 2、4、6、8、10、12 共 6 次比较后,在索引 6 处找到 14。查找 15 时,需要遍历整个数组(10 次比较)才能确认不存在。
二分搜索(迭代法)
二分搜索(迭代法)通过维护一个搜索范围 [low, high],每次取中间元素与目标值比较,根据比较结果将搜索范围缩小一半:
- 若中间值等于目标值,搜索成功。
- 若中间值小于目标值,说明目标在右半部分,将
low移到mid + 1。 - 若中间值大于目标值,说明目标在左半部分,将
high移到mid - 1。
以数组 [2, 4, 6, 8, 10, 12, 14, 16, 18, 20] 查找目标 14 为例:
数组: [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
索引: 0 1 2 3 4 5 6 7 8 9
第1步: low=0, high=9, mid=(0+9)/2=4
arr[4]=10 < 14 → 目标在右半部分,low=mid+1=5
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
^^^^^^^^^^^^^^^^^^^^
搜索范围 [5, 9]
第2步: low=5, high=9, mid=(5+9)/2=7
arr[7]=16 > 14 → 目标在左半部分,high=mid-1=6
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
^^^
搜索范围 [5, 6]
第3步: low=5, high=6, mid=(5+6)/2=5
arr[5]=12 < 14 → 目标在右半部分,low=mid+1=6
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
^
搜索范围 [6, 6]
第4步: low=6, high=6, mid=(6+6)/2=6
arr[6]=14 == 14 → 找到目标!返回索引 6
仅用 4 次比较就找到了目标,而线性搜索也需要 7 次比较。
C++ 实现
#include <iostream>
// binary search (iterative): halve the range each step
int binarySearch(int arr[], int n, int target)
{
int low = 0;
int high = n - 1;
while (low <= high)
{
int mid = low + (high - low) / 2; // avoid overflow
if (arr[mid] == target)
{
return mid; // found
}
else if (arr[mid] < target)
{
low = mid + 1; // search right half
}
else
{
high = mid - 1; // search left half
}
}
return -1; // not found
}
int main()
{
int arr[] = {2, 4, 6, 8, 10, 12, 14, 16, 18, 20};
int n = sizeof(arr) / sizeof(arr[0]);
// search for existing element
int target1 = 14;
int result1 = binarySearch(arr, n, target1);
if (result1 != -1)
{
std::cout << "Found " << target1 << " at index " << result1 << "\n";
}
else
{
std::cout << target1 << " not found in the array\n";
}
// search for non-existing element
int target2 = 15;
int result2 = binarySearch(arr, n, target2);
if (result2 != -1)
{
std::cout << "Found " << target2 << " at index " << result2 << "\n";
}
else
{
std::cout << target2 << " not found in the array\n";
}
return 0;
}
运行该程序将输出
Found 14 at index 6
15 not found in the array
C 实现
#include <stdio.h>
// binary search (iterative): halve the range each step
int binarySearch(int arr[], int n, int target)
{
int low = 0;
int high = n - 1;
while (low <= high)
{
int mid = low + (high - low) / 2; // avoid overflow
if (arr[mid] == target)
{
return mid; // found
}
else if (arr[mid] < target)
{
low = mid + 1; // search right half
}
else
{
high = mid - 1; // search left half
}
}
return -1; // not found
}
int main()
{
int arr[] = {2, 4, 6, 8, 10, 12, 14, 16, 18, 20};
int n = sizeof(arr) / sizeof(arr[0]);
// search for existing element
int target1 = 14;
int result1 = binarySearch(arr, n, target1);
if (result1 != -1)
{
printf("Found %d at index %d\n", target1, result1);
}
else
{
printf("%d not found in the array\n", target1);
}
// search for non-existing element
int target2 = 15;
int result2 = binarySearch(arr, n, target2);
if (result2 != -1)
{
printf("Found %d at index %d\n", target2, result2);
}
else
{
printf("%d not found in the array\n", target2);
}
return 0;
}
运行该程序将输出
Found 14 at index 6
15 not found in the array
Python 实现
def binary_search(arr, target):
"""Binary search (iterative): halve the range each step."""
low = 0
high = len(arr) - 1
while low <= high:
mid = low + (high - low) // 2 # avoid overflow
if arr[mid] == target:
return mid # found
elif arr[mid] < target:
low = mid + 1 # search right half
else:
high = mid - 1 # search left half
return -1 # not found
arr = [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
# search for existing element
target1 = 14
result1 = binary_search(arr, target1)
if result1 != -1:
print(f"Found {target1} at index {result1}")
else:
print(f"{target1} not found in the array")
# search for non-existing element
target2 = 15
result2 = binary_search(arr, target2)
if result2 != -1:
print(f"Found {target2} at index {result2}")
else:
print(f"{target2} not found in the array")
运行该程序将输出
Found 14 at index 6
15 not found in the array
Go 实现
package main
import "fmt"
// binary search (iterative): halve the range each step
func binarySearch(arr []int, target int) int {
low := 0
high := len(arr) - 1
for low <= high {
mid := low + (high-low)/2 // avoid overflow
if arr[mid] == target {
return mid // found
} else if arr[mid] < target {
low = mid + 1 // search right half
} else {
high = mid - 1 // search left half
}
}
return -1 // not found
}
func main() {
arr := []int{2, 4, 6, 8, 10, 12, 14, 16, 18, 20}
// search for existing element
target1 := 14
result1 := binarySearch(arr, target1)
if result1 != -1 {
fmt.Printf("Found %d at index %d\n", target1, result1)
} else {
fmt.Printf("%d not found in the array\n", target1)
}
// search for non-existing element
target2 := 15
result2 := binarySearch(arr, target2)
if result2 != -1 {
fmt.Printf("Found %d at index %d\n", target2, result2)
} else {
fmt.Printf("%d not found in the array\n", target2)
}
}
运行该程序将输出
Found 14 at index 6
15 not found in the array
Go 版本的迭代二分搜索使用 low + (high - low) / 2 计算中间位置以避免整数溢出,与 C++/Python 版本的逻辑完全一致。
查找 14 时经过 4 次比较即找到目标。查找 15 时,搜索范围逐步缩小至 low > high,确认 15 不在数组中。注意中间值的计算使用 low + (high - low) / 2 而非 (low + high) / 2,这是为了避免 low + high 在极大数组时发生整数溢出。
二分搜索(递归法)
递归法实现二分搜索的核心思想与迭代法相同,只是将"缩小搜索范围"的过程用递归调用替代:
- 基准情形(Base Case):当
low > high时,搜索范围为空,返回 -1 表示未找到。 - 递推步骤(Recursive Step):计算中间位置
mid,若中间值等于目标则返回;否则对左半部分或右半部分递归搜索。
以查找目标 14 为例,递归调用树如下:
binarySearchRecursive(arr, 0, 9, 14)
mid=4, arr[4]=10 < 14
└─ binarySearchRecursive(arr, 5, 9, 14)
mid=7, arr[7]=16 > 14
└─ binarySearchRecursive(arr, 5, 6, 14)
mid=5, arr[5]=12 < 14
└─ binarySearchRecursive(arr, 6, 6, 14)
mid=6, arr[6]=14 == 14
└─ return 6 ← found!
C++ 实现
#include <iostream>
// binary search (recursive): divide and conquer
int binarySearchRecursive(int arr[], int low, int high, int target)
{
// base case: search range is empty
if (low > high)
{
return -1; // not found
}
int mid = low + (high - low) / 2; // avoid overflow
if (arr[mid] == target)
{
return mid; // found
}
else if (arr[mid] < target)
{
// search right half
return binarySearchRecursive(arr, mid + 1, high, target);
}
else
{
// search left half
return binarySearchRecursive(arr, low, mid - 1, target);
}
}
int main()
{
int arr[] = {2, 4, 6, 8, 10, 12, 14, 16, 18, 20};
int n = sizeof(arr) / sizeof(arr[0]);
// search for existing element
int target1 = 14;
int result1 = binarySearchRecursive(arr, 0, n - 1, target1);
if (result1 != -1)
{
std::cout << "Found " << target1 << " at index " << result1 << "\n";
}
else
{
std::cout << target1 << " not found in the array\n";
}
// search for non-existing element
int target2 = 15;
int result2 = binarySearchRecursive(arr, 0, n - 1, target2);
if (result2 != -1)
{
std::cout << "Found " << target2 << " at index " << result2 << "\n";
}
else
{
std::cout << target2 << " not found in the array\n";
}
return 0;
}
运行该程序将输出
Found 14 at index 6
15 not found in the array
C 实现
#include <stdio.h>
// binary search (recursive): divide and conquer
int binarySearchRecursive(int arr[], int low, int high, int target)
{
// base case: search range is empty
if (low > high)
{
return -1; // not found
}
int mid = low + (high - low) / 2; // avoid overflow
if (arr[mid] == target)
{
return mid; // found
}
else if (arr[mid] < target)
{
// search right half
return binarySearchRecursive(arr, mid + 1, high, target);
}
else
{
// search left half
return binarySearchRecursive(arr, low, mid - 1, target);
}
}
int main()
{
int arr[] = {2, 4, 6, 8, 10, 12, 14, 16, 18, 20};
int n = sizeof(arr) / sizeof(arr[0]);
// search for existing element
int target1 = 14;
int result1 = binarySearchRecursive(arr, 0, n - 1, target1);
if (result1 != -1)
{
printf("Found %d at index %d\n", target1, result1);
}
else
{
printf("%d not found in the array\n", target1);
}
// search for non-existing element
int target2 = 15;
int result2 = binarySearchRecursive(arr, 0, n - 1, target2);
if (result2 != -1)
{
printf("Found %d at index %d\n", target2, result2);
}
else
{
printf("%d not found in the array\n", target2);
}
return 0;
}
运行该程序将输出
Found 14 at index 6
15 not found in the array
Python 实现
def binary_search_recursive(arr, low, high, target):
"""Binary search (recursive): divide and conquer."""
# base case: search range is empty
if low > high:
return -1 # not found
mid = low + (high - low) // 2 # avoid overflow
if arr[mid] == target:
return mid # found
elif arr[mid] < target:
# search right half
return binary_search_recursive(arr, mid + 1, high, target)
else:
# search left half
return binary_search_recursive(arr, low, mid - 1, target)
arr = [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
n = len(arr)
# search for existing element
target1 = 14
result1 = binary_search_recursive(arr, 0, n - 1, target1)
if result1 != -1:
print(f"Found {target1} at index {result1}")
else:
print(f"{target1} not found in the array")
# search for non-existing element
target2 = 15
result2 = binary_search_recursive(arr, 0, n - 1, target2)
if result2 != -1:
print(f"Found {target2} at index {result2}")
else:
print(f"{target2} not found in the array")
运行该程序将输出
Found 14 at index 6
15 not found in the array
Go 实现
package main
import "fmt"
// binary search (recursive): divide and conquer
func binarySearchRecursive(arr []int, low, high, target int) int {
// base case: search range is empty
if low > high {
return -1 // not found
}
mid := low + (high-low)/2 // avoid overflow
if arr[mid] == target {
return mid // found
} else if arr[mid] < target {
// search right half
return binarySearchRecursive(arr, mid+1, high, target)
} else {
// search left half
return binarySearchRecursive(arr, low, mid-1, target)
}
}
func main() {
arr := []int{2, 4, 6, 8, 10, 12, 14, 16, 18, 20}
n := len(arr)
// search for existing element
target1 := 14
result1 := binarySearchRecursive(arr, 0, n-1, target1)
if result1 != -1 {
fmt.Printf("Found %d at index %d\n", target1, result1)
} else {
fmt.Printf("%d not found in the array\n", target1)
}
// search for non-existing element
target2 := 15
result2 := binarySearchRecursive(arr, 0, n-1, target2)
if result2 != -1 {
fmt.Printf("Found %d at index %d\n", target2, result2)
} else {
fmt.Printf("%d not found in the array\n", target2)
}
}
运行该程序将输出
Found 14 at index 6
15 not found in the array
Go 递归版本的 binarySearchRecursive 函数接受切片和边界索引作为参数,逻辑与 C++/Python 递归版本完全等价。每次递归调用将搜索范围缩小一半,直到找到目标或范围为空。
递归法的逻辑与迭代法完全等价,只是将 while 循环替换为递归调用。每次递归调用将搜索范围缩小一半,直到找到目标或范围为空。注意递归法的空间复杂度为 O(log n)(递归调用栈),而迭代法仅为 O(1)。
完整对比
下面给出一个完整的程序,在同一数据集上同时运行线性搜索和二分搜索(迭代法、递归法),对比它们的搜索结果。
C++ 实现
#include <iostream>
// linear search
int linearSearch(int arr[], int n, int target)
{
for (int i = 0; i < n; i++)
{
if (arr[i] == target)
{
return i;
}
}
return -1;
}
// binary search (iterative)
int binarySearch(int arr[], int n, int target)
{
int low = 0;
int high = n - 1;
while (low <= high)
{
int mid = low + (high - low) / 2;
if (arr[mid] == target)
{
return mid;
}
else if (arr[mid] < target)
{
low = mid + 1;
}
else
{
high = mid - 1;
}
}
return -1;
}
// binary search (recursive)
int binarySearchRecursive(int arr[], int low, int high, int target)
{
if (low > high)
{
return -1;
}
int mid = low + (high - low) / 2;
if (arr[mid] == target)
{
return mid;
}
else if (arr[mid] < target)
{
return binarySearchRecursive(arr, mid + 1, high, target);
}
else
{
return binarySearchRecursive(arr, low, mid - 1, target);
}
}
int main()
{
int arr[] = {2, 4, 6, 8, 10, 12, 14, 16, 18, 20};
int n = sizeof(arr) / sizeof(arr[0]);
int targets[] = {14, 15, 2, 20};
int numTargets = sizeof(targets) / sizeof(targets[0]);
std::cout << "Array: ";
for (int i = 0; i < n; i++)
{
std::cout << arr[i];
if (i < n - 1) std::cout << " ";
}
std::cout << "\n\n";
for (int i = 0; i < numTargets; i++)
{
int t = targets[i];
int r1 = linearSearch(arr, n, t);
int r2 = binarySearch(arr, n, t);
int r3 = binarySearchRecursive(arr, 0, n - 1, t);
std::cout << "Target " << t << ":\n";
std::cout << " Linear Search: "
<< (r1 != -1 ? "index " + std::to_string(r1) : "not found") << "\n";
std::cout << " Binary Search (iter): "
<< (r2 != -1 ? "index " + std::to_string(r2) : "not found") << "\n";
std::cout << " Binary Search (rec): "
<< (r3 != -1 ? "index " + std::to_string(r3) : "not found") << "\n";
std::cout << "\n";
}
return 0;
}
运行该程序将输出
Array: 2 4 6 8 10 12 14 16 18 20
Target 14:
Linear Search: index 6
Binary Search (iter): index 6
Binary Search (rec): index 6
Target 15:
Linear Search: not found
Binary Search (iter): not found
Binary Search (rec): not found
Target 2:
Linear Search: index 0
Binary Search (iter): index 0
Binary Search (rec): index 0
Target 20:
Linear Search: index 9
Binary Search (iter): index 9
Binary Search (rec): index 9
C 实现
#include <stdio.h>
// linear search
int linearSearch(int arr[], int n, int target)
{
for (int i = 0; i < n; i++)
{
if (arr[i] == target)
{
return i;
}
}
return -1;
}
// binary search (iterative)
int binarySearch(int arr[], int n, int target)
{
int low = 0;
int high = n - 1;
while (low <= high)
{
int mid = low + (high - low) / 2;
if (arr[mid] == target)
{
return mid;
}
else if (arr[mid] < target)
{
low = mid + 1;
}
else
{
high = mid - 1;
}
}
return -1;
}
// binary search (recursive)
int binarySearchRecursive(int arr[], int low, int high, int target)
{
if (low > high)
{
return -1;
}
int mid = low + (high - low) / 2;
if (arr[mid] == target)
{
return mid;
}
else if (arr[mid] < target)
{
return binarySearchRecursive(arr, mid + 1, high, target);
}
else
{
return binarySearchRecursive(arr, low, mid - 1, target);
}
}
int main()
{
int arr[] = {2, 4, 6, 8, 10, 12, 14, 16, 18, 20};
int n = sizeof(arr) / sizeof(arr[0]);
int targets[] = {14, 15, 2, 20};
int numTargets = sizeof(targets) / sizeof(targets[0]);
printf("Array: ");
for (int i = 0; i < n; i++)
{
printf("%d", arr[i]);
if (i < n - 1) printf(" ");
}
printf("\n\n");
for (int i = 0; i < numTargets; i++)
{
int t = targets[i];
int r1 = linearSearch(arr, n, t);
int r2 = binarySearch(arr, n, t);
int r3 = binarySearchRecursive(arr, 0, n - 1, t);
printf("Target %d:\n", t);
printf(" Linear Search: %s\n",
r1 != -1 ? "found" : "not found");
printf(" Binary Search (iter): %s\n",
r2 != -1 ? "found" : "not found");
printf(" Binary Search (rec): %s\n",
r3 != -1 ? "found" : "not found");
printf("\n");
}
return 0;
}
运行该程序将输出
Array: 2 4 6 8 10 12 14 16 18 20
Target 14:
Linear Search: found
Binary Search (iter): found
Binary Search (rec): found
Target 15:
Linear Search: not found
Binary Search (rec): not found
Binary Search (rec): not found
Target 2:
Linear Search: found
Binary Search (iter): found
Binary Search (rec): found
Target 20:
Linear Search: found
Binary Search (iter): found
Binary Search (rec): found
Python 实现
def linear_search(arr, target):
"""Linear search."""
for i in range(len(arr)):
if arr[i] == target:
return i
return -1
def binary_search(arr, target):
"""Binary search (iterative)."""
low = 0
high = len(arr) - 1
while low <= high:
mid = low + (high - low) // 2
if arr[mid] == target:
return mid
elif arr[mid] < target:
low = mid + 1
else:
high = mid - 1
return -1
def binary_search_recursive(arr, low, high, target):
"""Binary search (recursive)."""
if low > high:
return -1
mid = low + (high - low) // 2
if arr[mid] == target:
return mid
elif arr[mid] < target:
return binary_search_recursive(arr, mid + 1, high, target)
else:
return binary_search_recursive(arr, low, mid - 1, target)
arr = [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
targets = [14, 15, 2, 20]
print(f"Array: {' '.join(str(x) for x in arr)}\n")
for t in targets:
r1 = linear_search(arr, t)
r2 = binary_search(arr, t)
r3 = binary_search_recursive(arr, 0, len(arr) - 1, t)
print(f"Target {t}:")
print(f" Linear Search: {'index ' + str(r1) if r1 != -1 else 'not found'}")
print(f" Binary Search (iter): {'index ' + str(r2) if r2 != -1 else 'not found'}")
print(f" Binary Search (rec): {'index ' + str(r3) if r3 != -1 else 'not found'}")
print()
运行该程序将输出
Array: 2 4 6 8 10 12 14 16 18 20
Target 14:
Linear Search: index 6
Binary Search (iter): index 6
Binary Search (rec): index 6
Target 15:
Linear Search: not found
Binary Search (iter): not found
Binary Search (rec): not found
Target 2:
Linear Search: index 0
Binary Search (iter): index 0
Binary Search (rec): index 0
Target 20:
Linear Search: index 9
Binary Search (iter): index 9
Binary Search (rec): index 9
Go 实现
package main
import (
"fmt"
"strconv"
"strings"
)
// linear search
func linearSearch(arr []int, target int) int {
for i := 0; i < len(arr); i++ {
if arr[i] == target {
return i
}
}
return -1
}
// binary search (iterative)
func binarySearch(arr []int, target int) int {
low := 0
high := len(arr) - 1
for low <= high {
mid := low + (high-low)/2
if arr[mid] == target {
return mid
} else if arr[mid] < target {
low = mid + 1
} else {
high = mid - 1
}
}
return -1
}
// binary search (recursive)
func binarySearchRecursive(arr []int, low, high, target int) int {
if low > high {
return -1
}
mid := low + (high-low)/2
if arr[mid] == target {
return mid
} else if arr[mid] < target {
return binarySearchRecursive(arr, mid+1, high, target)
} else {
return binarySearchRecursive(arr, low, mid-1, target)
}
}
func formatResult(idx int) string {
if idx != -1 {
return "index " + strconv.Itoa(idx)
}
return "not found"
}
func main() {
arr := []int{2, 4, 6, 8, 10, 12, 14, 16, 18, 20}
targets := []int{14, 15, 2, 20}
strArr := make([]string, len(arr))
for i, v := range arr {
strArr[i] = strconv.Itoa(v)
}
fmt.Printf("Array: %s\n\n", strings.Join(strArr, " "))
for _, t := range targets {
r1 := linearSearch(arr, t)
r2 := binarySearch(arr, t)
r3 := binarySearchRecursive(arr, 0, len(arr)-1, t)
fmt.Printf("Target %d:\n", t)
fmt.Printf(" Linear Search: %s\n", formatResult(r1))
fmt.Printf(" Binary Search (iter): %s\n", formatResult(r2))
fmt.Printf(" Binary Search (rec): %s\n", formatResult(r3))
fmt.Println()
}
}
运行该程序将输出
Array: 2 4 6 8 10 12 14 16 18 20
Target 14:
Linear Search: index 6
Binary Search (iter): index 6
Binary Search (rec): index 6
Target 15:
Linear Search: not found
Binary Search (iter): not found
Binary Search (rec): not found
Target 2:
Linear Search: index 0
Binary Search (iter): index 0
Binary Search (rec): index 0
Target 20:
Linear Search: index 9
Binary Search (iter): index 9
Binary Search (rec): index 9
三种搜索方法对每个目标的搜索结果完全一致,验证了算法的正确性。对于目标 14,三种方法均返回索引 6;对于不存在的目标 15,均返回"未找到"。边界情况(首元素 2 和末元素 20)也能正确处理。
性能对比
| 指标 | 线性搜索 | 二分搜索(迭代) | 二分搜索(递归) |
|---|---|---|---|
| 最好时间复杂度 | O(1)(第一个元素即为目标) | O(1)(中间元素即为目标) | O(1)(中间元素即为目标) |
| 平均时间复杂度 | O(n) | O(log n) | O(log n) |
| 最坏时间复杂度 | O(n)(目标不存在或在末尾) | O(log n) | O(log n) |
| 空间复杂度 | O(1) | O(1) | O(log n)(递归调用栈) |
| 前提条件 | 无(任意数组均可) | 数组必须已排序 | 数组必须已排序 |
| 实现难度 | 简单 | 中等 | 中等 |
何时使用线性搜索
- 数组未排序,或排序的代价(O(n log n))高于直接搜索。
- 数组规模很小(例如少于 10 个元素),线性搜索的实际开销可能低于二分搜索。
- 只需查找第一个匹配项,或需要找到所有匹配项。
- 数据只搜索一次,不值得预先排序。
何时使用二分搜索
- 数组已排序且需要多次搜索,二分搜索的高效性会充分体现。
- 数据规模较大(数千或更多元素),O(log n) 的优势显著。
- 追求搜索性能,且可以接受排序的预处理开销。
- 优先选择迭代法实现,因为空间复杂度更低(O(1) vs O(log n)),且不存在栈溢出风险。
数据规模对比
下表展示了不同数据规模下,线性搜索和二分搜索在最坏情况下的比较次数:
| 数据规模 n | 线性搜索(最坏) | 二分搜索(最坏) |
|---|---|---|
| 10 | 10 | 4 |
| 100 | 100 | 7 |
| 1,000 | 1,000 | 10 |
| 1,000,000 | 1,000,000 | 20 |
| 1,000,000,000 | 1,000,000,000 | 30 |
可以看出,随着数据规模的增长,二分搜索的优势呈指数级扩大。在 10 亿个元素中查找,线性搜索最坏需要 10 亿次比较,而二分搜索仅需 30 次。

浙公网安备 33010602011771号