二分搜索也叫折半搜索,算法本质是分而治之,通过不断缩小范围来搜索。二分搜索只实用于有序数组。
int binarySearch(int[] x, final int n) {
if (x == null || x.length == 0) {
return -1;
}
int p = 0, q = x.length - 1;
while (p <= q) {
int m = p + (q - p) / 2;
if (x[m] == n) {
return m;
} else if (x[m] < n) {
p = m + 1;
} else {
q = m - 1;
}
}
return -1;
}
测试用例需要考虑的边界情况:长度是1或2的数组,处理处理不好,可能出现死循环。
从这段代码可以看出,排序的意义之一就是为了便于搜索。
下面给出递归版本:
int binarySearch(int[] x, final int n, int p, int q) {
if (x == null || x.length == 0 || p > q) {
return -1;
}
int m = p + (q - p) / 2;
if (x[m] == n) {
return m;
} else if (x[m] < n) {
return binarySearch(x, n, m + 1, q);
} else {
return binarySearch(x, n, p, m - 1);
}
}
在一个线性结构中,可能出现重复的元素,返回的下表,可能是随机一个索引。现在期望返回下表最小的索引:
int binarySearchForFirstKey(int[] x, final int n) {
if (x == null || x.length == 0) {
return -1;
}
int p = 0, q = x.length - 1;
while (p <= q) {
int m = p + (q - p) / 2;
if (x[m] == n) {
if (m == 0 || x[m] > x[m - 1]) {
return m;
} else {
q = m - 1;
}
} else if (x[m] < n) {
p = m + 1;
} else {
q = m - 1;
}
}
return -1;
}
至于返回最右索引的代码省略。
参考:《剑指offer》38题