折半查找(二分查找)

目录

一、引入

二、思路分析

第一次计算

第二次计算

第三次计算

第四次计算

三、代码实现

1. 部分代码分析

2. 最终代码

四、比较


一、引入

编写代码在一个整形有序数组中查找具体的某个数
要求:找到了就打印数字所在的下标,找不到则输出:找不到。

例:

一般来说,这样的问题很好实现,可以通过对数组的每个元素挨个挨个比较,从而找到所需数字。如以下代码:

#include<stdio.h>
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		if (arr[i] == 7)
		{
			printf("找到了,下标是:%d", i);
			break;
		}
	}
	return 0;
}

当然这样的代码是正确的,但是如果当所查找的有序数组元素数量很大时,这样的代码就会运行很长时间,它的效率就会很低。

因此为了提高查找的效率,折半查找(也叫二分查找)就有了很大的用途,能够大大提高查找效率。

二、思路分析

简而言之,折半查找(二分查找)就是不断将数据变为原来的一半进行查找。

那么现在就以以下问题来一步步分析折半查找(二分查找)

第一步,将最左边的下标设为left,最右边的下标设为right。

这里肯定会问:为什么是下标?

因为我们在访问数组时是通过下标完成的。

然后设中间项为mid,它的计算方式为mid = (left+right) / 2

第一次计算

这里可以发现下标mid=4,arr[4]=5<7,说明要查找的数字 "7" 在5的右边,所以arr数组中的1~5都可以舍去不看了。即:

再看剩下的数字,那么此时left和right的位置也会发生改变。

第二次计算

这里可以发现下标mid=7,arr[7]=8>7,说明要查找的数字 "7" 在8的左边,所以arr数组中的8~10都可以舍去不看了,现在剩下了“ 6,7 ”了 。即:

看剩下的数字,此时left和right的位置发生改变:

第三次计算

此时下标mid=5,arr[5]=6<7,说明要查找的数字 "7" 在8的右边,所以arr数组中的“ 6 ”就可以舍去不看了,现在剩下了“ 7 ”了 。即:

看剩下的数字,此时left和right的位置发生改变:

第四次计算

这时算法结束,7就被找到了。

三、代码实现

通过上述对列举的描述,想必我们已经知道了大致的方向了吧,那么现在来进行代码实现。

1. 部分代码分析

首先,这个算法的每一步计算都时再找left、right,从而找到mid,利用不断地舍去一半的数据,进而精确数据位置,找到它。

以下是大致思路的部分代码:

//数据声明
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int left = 0;
int right = 9;
int mid = 0;
int key = 7;  //要查找的数为:7

//下面是只计算一次的代码实现
mid = (left + right) / 2;
if (arr[mid] < key)
{
    left = mid + 1;
}
else if (arr[mid] > key)
{
    right = mid - 1;
}
else
{
    printf("找到了,下标是:%d\n", mid);
    break;
}

可以发现,这个代码只是【二、思路分析】中的一步计算,通过 第二点的思路分析 可以知道这个操作需要重复执行,一直到满足 left = right 时才结束。故有以下代码:

#include<stdio.h>
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int left = 0;
	int right = 9;
	int mid = 0;
	int key = 7;  //要查找的数为:7

	while (left <= right)
	{
		mid = (left + right) / 2;
		if (arr[mid] < key)
		{
			left = mid + 1;
		}
		else if (arr[mid] > key)
		{
			right = mid - 1;
		}
		else
		{
			printf("找到了,下标是:%d\n", mid);
			break;
		}
	}
	return 0;
}

通过上述代码便可以实现查找这个有序数组中有的数据了,但是如果要查找的数据不在这个数组中,这又该怎么办?

这时,我们可以设一个标志sign,先令sign=0,这时当执行到了 left = right 时,且满足条件arr[mid] = key (key为要查找的数),再再将令 sign = 1。这样就代表了当整个程序都找完了的时候,如果要查找的数再数组arr中,sign 就会变为1,若没有,则为 0,通过判断sign是否为1,就能知道要查找的数是否找到。

2. 最终代码

所以整个代码应为:

#include<stdio.h>
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int left = 0;
	int right = 9;
	int mid = 0;
	int key = 7;  //要查找的数为:7
	int sign = 0;
	while (left <= right)
	{
		mid = (left + right) / 2;
		if (arr[mid] < key)
		{
			left = mid + 1;
		}
		else if (arr[mid] > key)
		{
			right = mid - 1;
		}
		else
		{
			printf("找到了,下标是:%d\n", mid);
			sign = 1;
			break;
		}
	}
	if (sign == 0)
		printf("找不到\n");
	return 0;
}

四、比较

#include<stdio.h>
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		if (arr[i] == 7)
		{
			printf("找到了,下标是:%d", i);
			break;
		}
	}
	return 0;
}

对于这个代码而言,它需要从arrr[0]开始找,待找到7时需要找7次。

对于这个问题,若用折半查找(二分查找)的话,则只需要找四次。

这就大大提高了查找效率。试想一下如果在有40亿的数据中去查找一个数(这个数在这40亿的数字中的靠后位置),如果用常规方法,那么查找的次数就是一个非常庞大的数字了。但是如果用折半查找(二分查找),在其计算的第一次时就可以排除20亿的数据了,这是查找的次数就是一个比较小的数字了,故而大大提高了查找效率。

因此,折半查找(二分查找)何乐而不为呢 ?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值