当前位置:   article > 正文

最简单最快的查找算法——二分查找(基础)-c/c++_最快的查询算法方法是

最快的查询算法方法是

二分查找(基础)

本篇采用的计算机语言是c语言,过程中会出现c++的部分函数,函数功能都会有所提示,如果你不会c语言也没关系,代码数量不多,主要是理解算法的实现过程。

一个例子

我想,大家都玩过猜数字的游戏吧:从1~100中想一个数字,玩家进行猜测,每次猜测都要给玩家一个提示:大了、小了。如果我们从1开始猜,就会出现一下场景:
A:1
B:小了
A:2
B:小了
A:3
B:小了
……
这样,我们最多可能会猜测99次!!这是个很麻烦的事,但是如果我们这样猜:
A:50(1-100的中间数)
B:小了
A:75(50-100的中间数)
B:大了
A:63(50-75的中间数)
B:大了
A:57
B:对了!

这,就是二分查找,你已经学会这个算法的理论部分了!

每次猜测可以排除的数字个数如下:
100个元素-(第一步)-> 50-(第二步)->25-(第三步)->13-(第四步)->7-(第五步)->4-(第六步)->2-(第七步)->1(每次使用二分查找时都可以排除一半的数字)
这样,不管我心里想的是哪个数字,你都能在七次以内猜到,因为每次猜测都可以排除很多数字!

另一个例子

如果我们要从一本包含240000个字的字典里找到一个汉字,如果采用传统的连续查找最多需要240000次!!!(我想谁都不会这么无聊)。
所以我们如果采用二分查找的方法,最多查找多少次呢?

240000-120000-60000-30000-15000-7500-3750-1875-937-468-234-117-58-29-14-7-3-1
不用数了,我已经帮你数好了!最多需要17步就可以找到你想要的那个字了!

由此可见,二分查找极大的减少了我们查找的次数,这放在计算机上,就会极大的优化我们程序的运行时间!

运行时间:O(n)->O(log2n)

大家都知道log2n会随着n的增长逐渐与n拉开差距吧!
在这里插入图片描述那么问题来了
Q:我们如果想找一个有序数列中的一个数怎么办呢?

A:我们应该先知道这个数列有多少位数字,通过计算(下标为:头部下标加尾部下标/2)找到中间的那个数字(后面我们称中间数),再比较需要找的数字和中间数的大小,如果需要找的数字大于中间数,那么中间数就要更改为:(前任中间数下标+1(因为我们已经知道前任中间数不是我们要找的数,所以我们从它的下一个数开始找)+尾部下标)/2,理所当然我们的头部下标就要更改为:前任中间数的下标+1。反之,我们把尾部下标改为前任中间数下标-1。我们重复这个过程,直到找到那个数字,或者找了一遍都没有找到这个数字,此时头部和尾部下标应该重合。

可能你看了上面那段文字仍旧不够理解,那么接下来请看代码部分!

我们通过从某一个数组内查找某一个数并返回为例子:
题目如下:

输入一个数字n表示一个数组的大小,下一行来输入n个数字(数字用空格隔开)表示数组的数据,接下来输入一个数字k,表示要查找的数字。
如果这个数字存在,则返回YES,否则返回NO。
Input
5
1 2 3 4 5
3
Output
YES
Input
5
1 2 3 4 5
9
Output
NO

#include<stdio.h>
#include<algorithm>//排序函数所在的函数库
using namespace std;//排序函数要用到的

int a[1000000];
int bs(int tail,int num){//bs是二分查找英文缩写,这个你可以根据自己的喜好来自定义你的函数名称。首先给函数一个尾部下标tail,表示一个数组的大小,num为你要查找的数字。
	int head = 0;//我们默认数组下标从0开始
	while(tail>=head){//每次查找玩如果不是想查找的那个数字,都要更新中间数,我们通过更新尾部和头部下标来更新中间数,直到头部和尾部重合都没找到这个数字,说明这个数字不存在。
		int mid = head+(tail-head)/2;//当然我们可以用mid=(head+tail)/2,这是另外一种写法,防止head+tail太大而导致程序无法运行。
		if(num==a[mid]){
			return 1;//如果我们要找的数字找到了,就返回1;
		}
		else if(num>a[mid]){
			head = mid + 1;//我们要找的数字比中间数大,所以我们也就把头部下标移动到中间数+1位置,将下次计算的中间数增加。
		}
		else{
			tail = mid - 1;//反之,我们要减小中间数。
		}
	}
	return 0;//如果tail==head了,说明这个数组里没有我们要找的那个数字,返回0
}

int main(){
	int n;
	scanf("%d",&n);//输入n
	for(int i=0;i<n;i++){
		scanf("%d",&a[i]);//以此输入数组内容
	}
	sort(a,a+n);//排序函数,为了防止输入的数据不是有序数列,若无序数列我们将无法找到中间数。
	int k;
	scanf("%d",&k);//输入要找的数
	int flag=bs(n-1,k);//我们输入n个数,由于下标是从0开始,所以最后一个尾部下标应该是n-1.
	if(flag==1){
		printf("YES\n");
	}
	else{
		printf("NO\n");
	}
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

课下作业

输入一个数字n表示一个数组的大小,下一行来输入n个数字(数字用空格隔开)表示数组的数据,接下来输入一个数字k,表示要查找的数字。
如果这个数字存在,则输出这个数,否则输出离它最近的数字。
Input
5
1 2 3 4 5
3
Output
3
Input
5
1 2 3 4 5
9
Output
5

个人建议先跟着文章中的代码敲一遍,再去自己敲一遍,核心代码为函数bs部分,如果看到此处还不理解请在文章下方留言或私信我,我将为你一一解答。

答案:

#include<stdio.h>
#include<algorithm>
using namespace std;

int a[1000000];
int bs(int tail,int num){
	int head = 0;
	int mid;
	while(tail>=head){
		mid = head+(tail-head)/2;
		if(num==a[mid]){
			break;
		}
		else if(num>a[mid]){
			head = mid + 1;
		}
		else{
			tail = mid - 1;
		}
	}
	return mid;
}

int main(){
	int n;
	scanf("%d",&n);
	for(int i=0;i<n;i++){
		scanf("%d",&a[i]);
	}
	sort(a,a+n);
	int k;
	scanf("%d",&k);
	int flag=bs(n-1,k);
	printf("%d\n",a[flag]);
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

博主也在努力的学习算法,希望我们可以共同进步!!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/人工智能uu/article/detail/961146
推荐阅读
相关标签
  

闽ICP备14008679号