这是一个递归版本的二分搜索。
稍微调整一下这个版本将为您提供最后一个索引或第一个索引,而零工作量和相同的复杂度 O(log-n)。
原来的二分查找递归版本是这样的:
public static int binarySearch(List<Integer> a, int startIndex, int endIndex, int key) {
int midIndex = (endIndex - startIndex)/2 + startIndex;
if (a.get(midIndex) == key) // found!
return midIndex;
if (startIndex == endIndex || startIndex == endIndex - 1)
return -1;
else if (a.get(midIndex) > key) // Search in the left
return binarySearch(a, 0, midIndex, key);
else if (a.get(midIndex) < key) // Search in the right
return binarySearch(a, midIndex, endIndex, key);
else
return -1; // not found
}
对第一个if语句稍作改动,就可以得到第一个索引:
public static int binarySearchLowIndex(List<Integer> a, int startIndex, int endIndex, int key) {
int midIndex = (endIndex - startIndex)/2 + startIndex;
if (a.get(midIndex) == key && a.get(midIndex - 1) != key) // found!
return midIndex;
if (startIndex == endIndex || startIndex == endIndex - 1)
return -1;
else if (a.get(midIndex) >= key) // Search in the left
return binarySearchLowIndex(a, 0, midIndex, key);
else if (a.get(midIndex) < key) // Search in the right
return binarySearchLowIndex(a, midIndex, endIndex, key);
else
return -1; // not found
}
最后一个索引也是如此:
public static int binarySearchHighIndex(List<Integer> a, int startIndex, int endIndex, int key) {
int midIndex = (endIndex - startIndex)/2 + startIndex;
if (a.get(midIndex) == key **&& a.get(midIndex + 1) != key**) // found!
return midIndex;
if (startIndex == endIndex || startIndex == endIndex - 1)
return -1;
else if (a.get(midIndex) > key) // Search in the left
return binarySearchHighIndex(a, 0, midIndex, key);
else if (a.get(midIndex) <= key) // Search in the right
return binarySearchHighIndex(a, midIndex, endIndex, key);
else
return -1; // not found
}
以下是一些测试示例(基于 Junit):
@Test
public void binarySearchTest() {
assert(BinarySearch.binarySearch(Arrays.asList(5, 7, 7, 8, 8, 10), 0, 5, 5) == 0);
}
@Test
public void binarySearchLowIndexTest() {
assert(BinarySearch.binarySearchLowIndex(Arrays.asList(5, 8, 8, 8, 8, 10), 0, 5, 8) == 1);
}
@Test
public void binarySearchHighIndexTest() {
assert(BinarySearch.binarySearchHighIndex(Arrays.asList(5, 8, 8, 8, 8, 10), 0, 5, 8) == 4);
}