二分查找(Binary Search)是一种在有序数组中查找特定元素的搜索算法。它通过比较数组中间元素与目标值来工作,从而将搜索范围缩小到一半,也称折半查找,是一种非常高效的工作于有序数组的查找算法。本文主要介绍二分查找及其几个变种,包括基础版、改变版、平衡版和Java版,以及Leftmost与Rightmost的概念。这些变种可能涉及对基本二分查找算法的优化或特定应用场景的调整。均采用Java语言实现。
二分查找的时间复杂度为O(log n),其中n是数组中的元素数量。这使得它在处理大数据集时非常高效。然而,二分查找要求数组必须是有序的,否则无法正确工作。
小细节:
在Java中,使用 >>> 无符号右移操作符来计算两个整数的平均值而不使用 “( j + i ) / 2” ,主要是出于以下几个原因:
在二分查找中,我们通常需要计算数组的中间索引,如下所示:
int low = 0;
int high = array.length - 1;
while (low <= high) {
int mid = (low + high) >>> 1; // 进行比较和搜索操作
}
在这个例子中,low 和 high 分别是搜索范围的起始和结束索引。使用 >>> 确保了即使 low 和 high 的和是一个奇数,计算出的 mid 也是一个有效的整数索引。(Java会自动将结果向下取整)
总的来说,使用 >>> 无符号右移在Java中计算两个整数的平均值,是一种高效且安全的方法,特别是在需要处理大量数据或性能敏感的场合。
在有序数组 A 内,查找值 target
public static int binarySearch(int[] a, int target) {
int i = 0, j = a.length - 1;
while (i <= j) {
int m = (i + j) >>> 1;
if (target < a[m]) { // 在左边
j = m - 1;
} else if (a[m] < target) { // 在右边
i = m + 1;
} else {
return m;
}
}
return -1;
}
另一种写法
在有序数组 A 内,查找值 target
public static int binarySearch(int[] a, int target) {
int i = 0, j = a.length;
while (i < j) {
int m = (i + j) >>> 1;
if (target < a[m]) { // 在左边
j = m;
} else if (a[m] < target) { // 在右边
i = m + 1;
} else {
return m;
}
}
return -1;
}
在有序数组 A 内,查找值 target
public static int binarySearchBalance(int[] a, int target) {
int i = 0, j = a.length;
while (1 < j - i) {
int m = (i + j) >>> 1;
if (target < a[m]) {
j = m;
} else {
i = m;
}
}
return (a[i] == target) ? i : -1;
}
思想:
以下是Java内部的二分查找算法
private static int binarySearch0(long[] a, int fromIndex, int toIndex,
long key) {
int low = fromIndex;
int high = toIndex - 1;
while (low <= high) {
int mid = (low + high) >>> 1;
long midVal = a[mid];
if (midVal < key)
low = mid + 1;
else if (midVal > key)
high = mid - 1;
else
return mid; // key found
}
return -(low + 1); // key not found.
}
有时我们希望返回的是最左侧的重复元素,如果用 基础二分查找
以下是返回最左侧元素索引:
public static int binarySearchLeftmost1(int[] a, int target) {
int i = 0, j = a.length - 1;
int candidate = -1;
while (i <= j) {
int m = (i + j) >>> 1;
if (target < a[m]) {
j = m - 1;
} else if (a[m] < target) {
i = m + 1;
} else {
candidate = m; // 记录候选位置
j = m - 1; // 继续向左
}
}
return candidate;
}
以下是返回最右侧元素索引:
public static int binarySearchRightmost1(int[] a, int target) {
int i = 0, j = a.length - 1;
int candidate = -1;
while (i <= j) {
int m = (i + j) >>> 1;
if (target < a[m]) {
j = m - 1;
} else if (a[m] < target) {
i = m + 1;
} else {
candidate = m; // 记录候选位置
i = m + 1; // 继续向右
}
}
return candidate;
}
对于 Leftmost 与 Rightmost,可以返回一个比 -1 更有用的值,小于 traget的元素个数
Leftmost 改为
public static int binarySearchLeftmost(int[] a, int target) {
int i = 0, j = a.length - 1;
while (i <= j) {
int m = (i + j) >>> 1;
if (target <= a[m]) {
j = m - 1;
} else {
i = m + 1;
}
}
return i;
}
Rightmost 改为
public static int binarySearchRightmost(int[] a, int target) {
int i = 0, j = a.length - 1;
while (i <= j) {
int m = (i + j) >>> 1;
if (target < a[m]) {
j = m - 1;
} else {
i = m + 1;
}
}
return i - 1;
}
以上就是关于二分查找算法的各个版本,感谢各位看官的观看,下期见,谢谢~