C语言二分查找,画图讲解

题目:用户输入一个数,在数组arr[] = {1,2,3,4,5,6,7,8,9,10}用二分查找来在这个数组中找到用户输入的值,能找到返回该数字的下标,找不到输出“找不到”
首先我们要了解什么是二分查找。大家一定玩过或听过数字炸弹这个游戏。在一个给定的范围中,在这些数中,有一个数字是炸弹(玩家不能猜到这个数字,猜到炸弹爆炸,游戏结束)。比如在1-100中,77是炸弹(玩家不知道这个数字)。然后开始猜。玩家1:猜50. 炸弹没炸,范围缩小到50-100.玩家2:猜75.炸弹没炸,范围缩小到75-100.玩家1:猜85。炸弹没炸范围缩小到75-85。玩家2:猜77.炸弹炸了,游戏结束。

其实上面描述的游戏过程其实就已经用上了二分法,玩家1和2在猜数字的时候都猜范围最中间的那个数。这样每次猜测都能缩小一半的范围。可以快速的找到数字。

我们要怎么完成题目中所描述的问题?二分查找的精髓就在二分。我们可以定义一个mid变量,给它赋值数组中间数字的下标。要想得到数组中间的下标,我们可以在定义两个变量left和right,给这两个变量分别赋值数组第一位元素的下标和数组最后一位元素的下标。这样我们就可以得到数组中间数字的下标。mid = (left + right) / 2;

int main()
{
	int arr[] = {1,2,3,4,5,6,7,8,9,10};
	int left = 0;

	return 0;
}

这里我们定义了left.但是right还没定义,我们现在想一下要如何定义right。在上面的描述中。我们说给right赋值数组最后一位元素的下标。这里的数组arr里面一共有10个元素。有的小伙伴就会说那直接给right赋值为9不就行了。其实确实是直接赋值9就行了。但要是我们看不见这个数组里有多少个元素那要怎么给right赋值呢?这里告诉大家一个办法。我们可以用sizeof运算符来计算数组的个数。
sizeof(arr)可以计算出这个数组的大小(单位为字节),然后我们可以再让sizeof计算这个数组里面的一个元素的大小。让两者相除就能得到这个数组里面的元素个数。我们把数组的第一个元素给sizeof计算。sizeof(arr[0])。我们定义变量sz(元素个数)来保存两者相除的值。在让right = sz - 1;(数组最后一位元素的下标为元素个数减1)

int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	int left = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);
	int right = sz - 1;
	int mid = (left + right) / 2;
	return 0;
}

接下来我们用画图来分析一下过程。假设要查找的数字为3.
在这里插入图片描述
若用户输入一个不在数组里的值会怎么样呢?这里假设用户输入20.我再画个图让大家看一下:

在这里插入图片描述
经过上面的过程可以发现,在查找的过程中,当left大于right时,我们就可以确认找不到这个值。所以left <= right可以作为我们循环查找数字的循环条件。

while(left <= right)
{
	;
}

现在我们要向循环语句中写if语句来查找。有三种情况:
1、mid所指向的元素arr[mid]小于num.此时的num在mid的右边,我们要缩小范围,让left移到mid右边一位,让mid重新指向新left和right中间的下标
2、mid所指向的元素arr[mid]大于num.此时的num在mid的左边,我们要缩小范围,让right移到mid左边一位,让mid重新指向新right和left中间的下标
3、mid所指向的元素arr[mid]等于num,查找的数字下标为当前mid。break跳出循环。
代码如下:

	while (left <= right)
	{
		if (arr[mid] < num)
		{
			left = mid + 1;
			mid = (left + right) / 2;
		}
		else if (arr[mid > num])
		{
			right = mid - 1;
			mid = (left + right) / 2;
		}
		else
		{
			printf("找到了,你找的数字下标为:%d", mid);
			break;
		}
	}
	return 0;
}

最后我们可以定义一个变量flag。令flag = 0;表示为找不到。若能找到,我们在最后的else中加一句flag = 1;在退出while循环后,判断一下flag的值,若为0.打印找不到,完整代码如下:

int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	int left = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);
	int right = sz - 1;
	int mid = (left + right) / 2;
	int flag = 0;
	int num = 0;
	printf("请输入你要查找的数字:");
	scanf("%d", num);
	while (left <= right)
	{
		if (arr[mid] < num)
		{
			left = mid + 1;
			mid = (left + right) / 2;
		}
		else if (arr[mid > num])
		{
			right = mid - 1;
			mid = (left + right) / 2;
		}
		else
		{
			printf("找到了,你找的数字下标为:%d", mid);
			flag = 1;
			break;
		}
	}
	if (flag == 0)
	{
		printf("找不到");
	}
	return 0;
}

带注释代码如下:

int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	int left = 0;
	//数组的最后一个元素的下标是数组的元素个数减去 - 1.
	//可以用sizeof(arr)计算出数组arr的大小(单位为字节)
	//sizeof(arr[0])可以计算出数组arr里面第一个元素的大小
	//用sizeof(arr) / sizeof(arr[0])就可以计算出数组元素个数,用变量sz来接收
	int sz = sizeof(arr) / sizeof(arr[0]);
	int right = sz - 1;
	int mid = (left + right) / 2;
	//定义一个flag变量,当flag = 0;时,找不到
	int flag = 0;
	int num = 0;
	printf("请输入你要查找的数字:");
	scanf("%d", num);
	while (left <= right)
	{
		if (arr[mid] < num)//当arr[mid] < num时,用户输入的数字在arr[mid]右边
		{
			left = mid + 1;//right移到mid的左边一位
			mid = (left + right) / 2;
		}
		else if (arr[mid > num])//当arr[mid] > num时,用户输入的数字在arr[mid]左边
		{
			right = mid - 1;//right移到mid的左边一位
			mid = (left + right) / 2;
		}
		else
		{
			printf("找到了,你找的数字下标为:%d", mid);
			flag = 1;
			break;
		}
	}
	//从while循环出来一共有两种情况
	//1.找到用户输入的数字,break跳出循环
	//2.找不到用户输入的数字,left > right,不满足循环条件退出循环
	if (flag == 0)
	{
		printf("找不到");
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值