本文介绍二分查找,并使用C++进行实现
二分查找
二分查找也称为折半查找,即每次查找的时候都从中间位置去查找,其要求线性表必须是顺序存储的(数组)结构,而且顺序表中的元素是有序排列的。
如下图就是一种满足折半查找要求的存储结构:
二分查找的步骤
我们令表中元素按升序排列,则二分查找的步骤为:
- 将中间位置的记录与给定数据进行比较,如果相等,则查找成功
- 否则使用中间位置将表分为两个子表
- 若给定数据大于中间位置元素,则从中间位置以后到结尾位置构成的子表中进行二分查找
- 若给定数据小于中间位置元素,则从开始位置到中间位置构成的子表中进行二分查找
- 重复以上过程,若找到,则查找成功;若查找到子表不存在,则给定数据不在表中
我们以在有序表8,12,20,68,76,89,91,120,155
查找68
为例子对以上过程进行说明(图中s
表示开始查找的位置,e
表示结尾查找的位置,mid
表示中间位置,我们令
m
i
d
=
⌊
(
s
+
e
)
/
2
⌋
mid=\lfloor (s+e)/2\rfloor
mid=⌊(s+e)/2⌋):
- 表长为
9
,中间位置为4
,将68
与第4
号的数据进行比较,不相等,68
小于76
,在左边子表中进行查找:e
变为3
- 表长为
4
,中间位置为1
,将68
与第1
号元素进行比较,不相等,68
大于12
,在右边子表中进行查找,s
变为2
- 表长为
2
,中间位置为2
,将68
与第2
号元素进行比较,不相等,68
大于12
,在右边子表中进行查找,s
变为3
- 表长为
1
,中间位置为3
,将68
与第3
号元素进行比较,相等,数据找到,返回数据位置
以上查找过程通过4
次查找到了想要查找的数据
二分查找的C++实现
以上例子中查到例子的代码如下:
#include <iostream>
using namespace std;
int s,e;
int bin_search(int arr[],int s,int e,int data){
if(s<=e){
int mid=(s+e)/2;
if (arr[mid]==data){
return mid;
}else if(data<arr[mid]){
e=mid-1;
bin_search(arr,s,e,data);
}else{
s=mid+1;
bin_search(arr,s,e,data);
}
}else{
return -1;
}
}
int main(){
int arr[]={8,12,20,68,76,89,91,120,155};
s=0,e=8;
cout<<"place="<<bin_search(arr,s,e,68);
return 0;
}
代码运行结果为:
place=3
猜数游戏
通过对二分查找的过程分析我们发现,对于一个数 n n n,我们采用二叉查找最多需要查找 ⌊ l o g 2 n ⌋ + 1 \lfloor log_2n \rfloor+1 ⌊log2n⌋+1次便可以找到该数。
那么假如有一个1000
以内的一个数,我们最多需要比较10
次就可以找到这个数,让我们换种玩法:
让别人先心里默念1000
以内的一个数,我们通过让这个人人说出与自己心里想的大小关系来猜数,在10
次以内我们必然猜到他心里想的数。
比较过程与查找类似,我们直接上代码:
#include <iostream>
#define Num 1000
using namespace std;
int choice,s,e,judge;
int arr[Num];
int guess(int s,int e){
if(s<=e){
cout<<"是"<<arr[(s+e)/2]<<"吗(1.是2.不是)?";
cin>>judge;
if(judge==1){
cout<<"哈哈哈,被我猜到了吧!"<<endl;
}else if(judge==2){
cout<<"大了还是小了?(1.大了2.小了)";
cin>>choice;
switch(choice){
case 1:
e=(s+e)/2-1;
guess(s,e);
break;
case 2:
s=(s+e)/2+1;
guess(s,e);
break;
default:
cout<<"输入有误,继续猜啊!\n";
guess(s,e);
break;
}
}else{
cout<<"输入有误,继续猜啊!\n";
guess(s,e);
}
}else{
cout<<"撒谎了还怎么玩游戏呢!\n"<<endl;
}
}
int main(){
for(int i=0;i<Num;i++)arr[i]=i+1;
s=0,e=999;
guess(s,e);
return 0;
}
让我们猜个999
玩一玩,猜的过程(运行结果)如下:
是500吗(1.是2.不是)?2
大了还是小了?(1.大了2.小了)2
是750吗(1.是2.不是)?2
大了还是小了?(1.大了2.小了)2
是875吗(1.是2.不是)?2
大了还是小了?(1.大了2.小了)2
是938吗(1.是2.不是)?2
大了还是小了?(1.大了2.小了)2
是969吗(1.是2.不是)?2
大了还是小了?(1.大了2.小了)2
是985吗(1.是2.不是)?2
大了还是小了?(1.大了2.小了)2
是993吗(1.是2.不是)?2
大了还是小了?(1.大了2.小了)2
是997吗(1.是2.不是)?2
大了还是小了?(1.大了2.小了)2
是999吗(1.是2.不是)?2
大了还是小了?(1.大了2.小了)2
是1000吗(1.是2.不是)?2
大了还是小了?(1.大了2.小了)2
撒谎了还怎么玩游戏呢!
可以看到我们在第九步
猜到了
才疏学浅,难免有错误和不当之处,欢迎交流批评指正!
同时有问题的话欢迎留言或邮箱联系(ljt_IT@163.com)。