【C语言】二分查找(折半查找)

目录

一、为什么要使用二分查找?

二、什么是二分查找?

三、二分查找的过程演示

四、代码呈现


一、为什么要使用二分查找?

题目:在一个有序数组中查找具体的某个数字n,并打印其下标。

在看到以上题目时,我们通常会使用遍历数组的方法来找到该元素,如下:

#include<stdio.h>
int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };  //有序数组
	int n = 7;  //要查找的数字
	int i = 0;
	int flag = 0;  //标记变量,判断是否找到该数字
	int sz = sizeof(arr) / sizeof(arr[0]);

	for (i = 0; i < sz; i++)
	{
		if (arr[i] == n)
		{
			printf("找到了,该数字的下标是%d\n", i);
			flag = 1;
			break;
		}
	}

	if (flag == 0)
	{
		printf("找不到该数字");
	}

	return 0;
}

这个方法是可行的,但如果数组元素非常非常多的时候,该方法的效率就变低了。

并且我们可以注意到题目给出的数组是有序的,我们可以将这个条件利用起来,通过二分查找法(也称折半查找法)提高效率

二、什么是二分查找?

        二分查找就是首先将数组的中间元素与要查找的数字进行比较,如果数字比中间元素小,我们接下来就在左半部分继续找该数字,如果数字比中间元素大,我们接下来就在右半部分继续找该数字,直到找到该数字为止。

三、二分查找的过程演示

        首先,我们要确定二分查找的左边界和右边界。因为我们要打印的是查找的数字在有序数组中的下标,所以用数组的下标来表示边界,将0作为左边界,右边界则是数组元素个数-1中间元素的下标则为(左边界+右边界)/2

        第一轮比较后,我们可以发现中间元素5比要找的数字7小,所以我们接下来在右半部分,即数字6~10之间继续找7。此时,左边界就变为下标5,即(mid+1),右边界不变。中间元素还是(left+right)/2。

        第二轮比较后,我们可以发现中间元素8比要找的数字7大,所以我们接下来要在左半部分,即数字6~7之间继续找7。此时,左边界不变,右边界变为下标6,即(mid-1)。中间元素还是(left+right)/2。

 

         第三轮比较后,我们发现中间元素6比要找的数字7小,所以我们接下来要在右半部分继续找7。此时,左边界变为下标6,即(mid+1),右边界不变。中间元素还是(left+right)/2。

         第四轮比较结束,我们找到了数字7,其下标为6。

由此可见,使用二分查找法,只需要四轮就可以将该数字找出来,而如果使用的是遍历数组的方法,则需要7轮才能找到。如果查找的数字在数组中靠后的位置或数组元素多的话,遍历次数就更多了。

在比较的过程中,我们可以思考一个问题:left和right都是int类型的数据,而int类型的数据是有取值范围的,如果left和right都是一个非常大的数字的话,相加后就有可能发生溢出,导致mid的数值出错。那我们该如何解决这个问题呢?

 

 我们可以将(right-left)多出来的部分除以2后,拿到left这块来,这样就可以避免溢出的情况。

最后我们可以得到:mid = left + (right-left) / 2

我们要注意的一点是,使用二分查找/折半查找的前提条件:数组是有序的

  • 通过上面的过程演示,我们可以知道二分查找中比较数值的过程是有多轮的,所以应该将其写成一个循环,且循环的条件为 left<=right
  • 在进入循环前,我们要先确定二分查找的左右边界,左边界为数组下标0,右边界为数组下标的最后一个数字,即元素个数-1。
  • 在每一轮的比较中,mid的值都在不断改变,所以我们应该将mid的赋值写在循环体内
  • 然后将下标为mid的元素与要查找的数字进行比较,如果arr[mid]小于该数字,接下来就改变left的赋值,在右半部分继续找该数字,如果arr[mid]大于该数字,接下来就改变right的赋值,在左半部分继续找该数字。
  • 在查找该数字的过程中,为了避免数值的溢出,mid = left + (right-left) / 2

最后,我们可以再对代码做一个小小的改进:将有序数组和查找的数字都从键盘输入。

 

四、代码呈现

题目:在一个有序数组中查找具体的某个数字n,并打印其下标。

#include<stdio.h>

int main()
{
	int arr[10] = { 0 };
	int n = 0;

	printf("请输入数组: ");
	for (int i = 0; i < 10; i++)  //输入有10个元素的有序数组
	{
		scanf("%d", &arr[i]);
	}

	printf("请输入要查找的数字: ");
	scanf("%d", &n);  //输入要查找的数字

	int left = 0;  //初始左边界
	int right = sizeof(arr) / sizeof(arr[0]) - 1;  //初始右边界
	int flag = 0;  //标记变量,判断是否找到该数字

	while (left <= right)
	{
		int mid = left + (right - left) / 2;

		if (arr[mid] < n)
		{
			left = mid + 1;
		}
		else if (arr[mid] > n)
		{
			right = mid - 1;
		}
		else
		{
			printf("找到了,该数字的下标是%d\n", mid);
			flag = 1;
			break;
		}
	}

	if (flag == 0)
		printf("找不到该数字\n");

	return 0;
}


以上是我对C语言中二分查找法/折半查找法的理解。

希望可以帮到大家!如果有写的不好的地方也希望大家指出,谢谢!

  • 13
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值