二分法查找:
1.适用情况:在一批有序数据中查找某数。
2.基本思想:选定这批数据中居中间位置的一个数与查找数比较,看是否为所找之数,若不是,利用数据的有序性,可以决定所找的数是在选定数之前还是之后,从而很快可以将查找范围缩小一半,就是一半一半的缩小范围,进而较快地找到目的数。
理论思想看似懵懵地,其实我已经很简结易懂的表达了,接着就拿例题来理解如何实现二分法查找。
例题:假设 数组a中的数据是按由小到大的顺序排序:-12,0,6,16,23,56,80,100,110,115;从键盘上输入一个数,判断该数是否在数组中,若在,输出所在序号。
【分析】a、首先 假设low,mid和high三个变量,分别只是数组中的起始元素、中间元素与最后一个元素的过程。本题如下图:(假设要查找的数为80)
因为mid=23,而不是所要的80.所以还要继续进行查找。
b、接着 要把范围缩小,如图所示:
c、因为b步骤中,80比mid=100小,所以新的查找区间在【56,80】,如图所示:
d、因为80大于mid=56,所以新的查找区间在【80】,如图所示:
此时,mid亦指向80,查找到此结束。
【C语言 代码】
#include <stdio.h>
#define M 10
void main(){
int a[M] = {
-12,0,6,16,23,56,80,100,110,115};
int n,flag,low,mig,high;
flag = 0;
low = 0;
high = M-1;
printf("Please input a number :\n");
scanf("%d",&n);
***while(low <= high){
mid = (low + high )/2;
if(n == mid){
flag = 1;
break;
}
else if(n > a[mid]){
low = mid + 1;
}
else high = mid - 1;
}***
if(flag == 1){
printf("The index of %d is %d",n,mid);
}
else printf("There is not %d",n);
}
上方代码的缺点在于 如果从键盘输入非法的(a,b,@等),则程序在运行时需把代码运行完输出结果,显知,这样运行的效率很低。因此,要从各方面考虑代码的效率,则将代码做进一步改正。
#include <stdio.h>
#define M 10
void main(){
int a[M] = {
-12,0,6,16,23,56,80,100,110,115};
int n,flag,low,mig,high;
flag = 0;
low = 0;
high = M-1;
printf("Please input a number :\n");
scanf("%d",&n);
#if (0) //宏定义:注释无用的代码块
do{
scanf("%d",&n);
getchar();
}while(n < a[0] || n > a[M-1]);
#endif
while( scanf("%d",&n) != 1){
//由于**scanf函数 是有返回值**的
printf("Illegal input !!\n\
Please input again!!\n");
getchar(); /*目的:把缓冲区的scanf函数的输入流
消耗完,否则就无法再次重新输入。*/
}
***while(low <= high){
mid = (low + high )/2;
if(n == mid){
flag = 1;
break;
}
else if(n > a[mid]){
low = mid + 1;
}
else high = mid - 1;
}***
if(flag == 1){
printf("The index of %d is %d",n,mid);
}
else printf("There is not %d",n);
}
【Java语言 代码】
//演示如何利用二分查找算法定位数组元素
public class BinaryChop {
public static void main(String[] args) {
int item = 0; // 随机数变量
int[] numbers = new int[20]; // 随机数构成的数组
// 以下生成一个包含随机整数的数组
loop: for (int i = 0; i < numbers.length; i++) {
item = new Random().nextInt(100); // 生成一个小于100的随机整数
for (int j = 0; j < i; j++) {
// 遍历数组进行检查,避免塞入重复数字
if (numbers[j] == item) {
// 已经存在该随机数,则继续第一层循环,重新生成随机数
i--; // 本次循环做了无用功,取消当前的计数
continue loop; // 直接继续上一级循环
}
}
numbers[i] = item; // 往数组填入新生成的随机数
}
Arrays.sort(numbers); // 对整数数组排序(默认升序排列)
for (int seq=0; seq<numbers.length; seq++) {
// 打印数组中的所有数字
System.out.println("序号="+seq+", 数字="+numbers[seq]);
}
System.out.println("最后生成的随机数="+item);
// 下面通过二分查找法确定目标数字排在第几位
int aim_item = item; // 最后生成的整数
System.out.println("准备查找的目标数字="+aim_item);
int start = 0; // 二分查找的开始位置
int end = numbers.length - 1; // 二分查找的结束位置
int middle = 0; // 开始位置与结束位置之间的中间位置
for (int count = 1, position = -1; start <= end; count++) {
middle = (start + end) / 2; // 折半获得中间的位置
System.out.println("折半查找的中间数字="+numbers[middle]);
if (numbers[middle] > aim_item) {
// 该位置的数字比目标数字大,表示目标数字在该位置左边
end = middle - 1;
} else if (numbers[middle] < aim_item) {
// 该位置的数字比目标数字大,表示目标数字在该位置右边
start = middle + 1;
} else {
// 找到目标数字,跳出循环
position = middle;
System.out.println("查找次数="+count+", 序号位置="+position);
break;
}
}
}
}