折半查找法也称为二分查找法,它充分利用了元素间的次序关系,采用分治策略,可在最坏的情况下用O(log n)完成搜索任务。
【基本思想】
将n个元素分成个数大致相同的两半,取a[n/2]与欲查找的x作比较,如果x=a[n/2]则找到x,算法终止。如果x<a[n/2],则我们只要在数组a的左半部继续搜索x(这里假设数组元素呈升序排列)。如果x>a[n/2],则我们只要在数组a的右半部继续搜索x。
二分搜索法的应用极其广泛,而且它的思想易于理解。第一个二分搜索算法早在1946 年就出现了,但是第一个完全正确的二分搜索算法直到1962年才出现。Bentley在他的著作《Writing Correct Programs》中写道,90%的计算机专家不能在2小时内写出完全正确的二分搜索算法。问题的关键在于准确地制定各次查找范围的边界以及终止条件的确定,正确地归纳奇偶数的各种情况,其实整理后可以发现它的具体算法是很直观的。
private static int[] dataArray;
public static int binarySearch(int x, int n) {
int left = 0;
int right = n - 1;
while(left <= right){
int middle = (left + right) / 2;
if( x == dataArray[middle]){
return middle;
}
if(x > dataArray[middle]){
left = middle + 1;
}
else {
right = middle - 1;
}
}
return -1;
}
public static void main(String[] args) {
dataArray = new int[]{8, 17, 26, 32, 40, 72, 87, 99};
System.out.println(binarySearch(48, 8));
}
变形,若找不到x,则输出与x最近的两个数。
可以证明:left指向大于x的第一个元素,right指向小于x的第一个元素。(为什么?迭代的最后一步必然是left和right指向同一元素,然后为什么会变得比right大呢?想想就明白了)
public static int binarySearch2(int x, int n) {
int left = 0;
int right = n - 1;
int min = 0;
int max = 0;
while(left <= right){
int middle = (left + right) / 2;
if( x == dataArray[middle]){
min = max = middle;
System.out.println("less is:" + min + "---more is:" + max);
return middle;
}
if(x > dataArray[middle]){
left = middle + 1;
}
else {
right = middle - 1;
}
}
max = (left >= n ? -1 : left);
min = (right >= n ? -1 : right);
System.out.println("less is:" + dataArray[min] + "---more is:" + dataArray[max]);
return -1;
}