一、二分查找
二分查找也被称为折半查找,是在一个有序数组中查找特定元素位置的查找算法。二分查找要求查找序列采用顺序存储,且按关键字有序排列
据说,二分查找最先出现在上个世纪50年代,但是直到60年代中期才出现了第一个正确的实现。在2006年,Java 库中关于二分查找的程序仍然因 Bug 的出现不得不被修复。实现一个完美的二分查找是有一定的难度的,要充分考虑到它的退出条件和中间点的计算。
二、二分查找算法必须基于有序序列
二分查找算法必须基于有序序列。这是因为二分查找算法的核心思想是通过比较目标值与数组中间元素的大小关系来确定下一步查找的范围。如果数组是无序的,那么无法通过比较中间元素和目标值的大小来缩小查找范围,因为无法保证数组中的元素按照一定的顺序排列。
如果在无序数组中使用二分查找算法,结果将是不可预测的,因为无法确定中间元素与目标值的大小关系。因此,在应用二分查找算法之前,必须确保待查找的数组是有序的,这样才能保证算法的正确性和效率。
三、算法思路
二分查找算法,也称为折半查找算法,是一种用于在有序数组中查找特定元素的高效算法。它的基本思想是通过不断将待查找区域分成两半,并根据目标值与中间元素的比较结果来确定下一步查找的区域,从而将查找范围逐渐缩小,直到找到目标元素或者确定目标元素不存在。
以下是二分查找算法的详细步骤:
- 初始化两个指针,一个指向数组的起始位置(通常记为
low
),另一个指向数组的结束位置(通常记为high
)。 - 在每一步中,计算中间位置的索引,通常为
(low + high) / 2
。 - 检查中间位置的元素与目标元素的值进行比较:
- 如果中间元素等于目标元素,则返回中间位置的索引。
- 从中间元素开始搜索。如果正好是要搜索元素,则搜索结束
- 如果中间元素大于目标元素,则更新
high
指针为中间位置的前一个位置。 - 如果中间元素小于目标元素,则更新
low
指针为中间位置的后一个位置。
- 如果中间元素等于目标元素,则返回中间位置的索引。
- 重复步骤 2 和步骤 3,直到找到目标元素或者确定目标元素不存在(即
low
指针大于high
指针)。- 如果不等,则在大于或者小于要搜索元素的那一半再执行二分查找
- 如果在某一步后要查找的数组为空,则代表找不到,可设为-1
二分查找算法的时间复杂度为 O(log n),其中 n 是数组的大小。这使得它比线性查找算法更加高效,特别是在大型数据集上。然而,二分查找要求数组必须是有序的,这是它的一个限制。
四、算法实现
1、python实现
from typing import Any, List
def binary_search(data: List[Any], item: Any):
"""
适用于升序序列
:param data:
:param item:
:return:
"""
# 将序列按照升序排序,增加程序健壮性
# data.sort()
# 初始化两个指针,一个指向数组的起始位置(通常记为low),另一个指向数组的结束位置(通常记为high)
low, high = 0, len(data) - 1
while low <= high:
mid = (low + high) // 2
if data[mid] == item:
return mid
elif data[mid] < item:
low = mid + 1
else:
high = mid - 1
return -1
if __name__ == '__main__':
print(binary_search([3, 6, 8, 9, 23], 23)) # 4
print(binary_search([23, 9, 8, 6, 3], 6)) # -1
print(binary_search([3, 6, 8, 9, 23, 88], 88)) # 5
2、java实现
public class BinarySearch {
public static int binarySearch(int[] data, int item){
//Arrays.sort(data);
int low = 0;
int high = data.length - 1;
while (low <= high){
int mid = (low + high) / 2;
if (data[mid] == item){
return mid;
} else if (data[mid] < item) {
low = mid + 1;
}else {
high = mid - 1;
}
}
return -1;
}
public static void main(String[] args) {
int[] data1 = {3, 6, 8, 9, 23};
int item1 = 9;
System.out.println(binarySearch(data1, item1)); // 3
int[] data2 = {23, 9, 8, 6, 3};
int item2 = 9;
System.out.println(binarySearch(data2, item2)); // -1
int[] data3 = {23, 9, 8, 6, 3, 88};
int item3 = 88;
System.out.println(binarySearch(data3, item3)); //5
}
}