一、概念
二分法又称折半查找法,它的基本原理是通过不断地比较目标元素与当前数组的中间值来更新左右界限,当找到目标元素或左边界与右边界重合时停止搜索。
听起来可能有点抽象,我们可以画一个图来理解它:
我们假设有三个指针:left,right、middle
分别指向当前的数组:array[0] array[length/2] array[length]
其中,length=array.length-1;
因为我们需要不断地对数组内容进行思想上的更新,即体现在改变left,right,middle三个变量的值上,而我们又无法改变array.length,为了方便理解和使用,用length来表示当前数组的长度。
而我们知道,数组的下标是从“0”开始的,因此要正确的得到middle以及right值,我们需要令length=array.length-1。
那么我们可以得出上图三个指针所指向的变量,那么此时假设我们要找的值num比3小
则我们可以将数组在思想上更新为下图:
需要注意的是,此时的middle所指向的“(1)”并不存在
我们知道在java中,如果你给一个int类型的变量赋值一个浮点数时,java会自动强转为int类型,此时会发生数据丢失或精度下降,即向下取整(假如是3.9取整后仍为3)。
所以此图中“(1)”只是为了告诉我们此时的middle=array[length/2]
而此时的length=(2-1)/2=0(0.5强转为0)
因此此时实际上left=middle=0,当前数组只有两个值:1,2
同理,若num等于当前middle(即num=1)则退出检索,并告知调用者是否找到目标元素 否则要么小于1(没有元素,告知调用者没有找到)
要么大于1(left,right,middle此时都只指向一个值:2)此时无论找没找到目标,都会退出检索,并告知结果。
二、特点
从以上内容中,我们可以看出二分法有几个明确的特点:
1、时间效率高:我们可以看到一旦目标元素小于(大于)当前middle值,则永远不会遍历大于(小于)middle值那一侧元素,相较于暴力遍历检索,大多数情况下能节省不少时间(比如要查找的元素在数组首位置则二分法更费时间);
2、需要传递一个有序数组:正因为二分法不会遍历不满足条件的那一侧的元素,所以一旦数组无序,也许永远无法找到我们需要的目标元素。
三、相关代码
import java.util.Scanner;
public class Text5 {
static int[] array = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("二分法查找");
int left=0;//左界
int right=array.length-1;//右界
int middle=array.length/2-1;//当前数组中间的值
System.out.println("请输入您需要查找的数字");
int num=sc.nextInt();//由用户输入想查找的数字
find(left,right,middle,num);
/*
find方法要做的事就是不断更新left,right,middle三个指针
因此我们还需要更新这三个指针时,只需要在find方法里重复调用find方法
即可
*/
}
public static void find(int left,int right,int middle,int num){
if(array[middle]==num){//表示已经找到元素,给出提示信息后结束
System.out.println("已找到"+array[middle]);
return;
}
if(left==right&&array[left]!=num){//若左右界重合还不相等,则表示没有这个元素
System.out.println("未找到"+num);
return;
}
if(num<array[middle]){//表示目标元素在此时数组左侧
find(left,middle,(left+right)/2,num);
//将right更新为middle,middle更新为当前数组的中间值
}
if(num>array[middle]){
find(middle+1,right,(left+right)/2,num);
}
}
}
试验样例:4
实验结果:已找到4
试验样例:11
实验结果:未找到11