7-二分查找

本文介绍了二分查找算法的基本思想和两种不同的比较策略,详细解释了如何在有序数组中高效地寻找目标值。当数组存在重复元素时,通过调整比较条件,可以获取目标值的起始和结束下标。最后,展示了结合两种策略优化后的代码实现,以处理重复元素的情况。
摘要由CSDN通过智能技术生成

这几天学习了一个新的算法—二分查找。进入主题,首先来看个问题:
对于下面这串有序的数组,我们怎么快速找到自己想要的数字的位置呢?
在这里插入图片描述
当然,最简单直接的方法是设计一个循环,一个一个地去将里面地数据区取出来,再与目标值进行比对,直到找到我们需要的数字。但这种方法有一个很大的问题:就是当数组很大的时候,我们要找的数字在数组的最后面,那么我们将会经历很多次循环才能找到我们的目标,这会造成工作效率的低下。

所以,为了提高效率,引入一种新的查找算法—二分查找

首先我们还是先来看看二分的思路:首先拿到一个有序的数表,我们首先访问它的中间元素,将中间元素与我们的目标值x进行比对,不符合条件的一半数组删除,直至数表只有最后一个元素,那么最后这个元素就是我们要找的元素。这里我们可以设计两种不同的比对方法,:

1:当前数表中间值小于等于x

  1. 即 当目标值大于或等于中间元素,则将数表的下边界修改为中间元素,上边界不变,继续相同操作;
  2. 当目标值小于中间元素,则将数表的上边界修改为中间元素减一,下边界不变,继续相同操作;

2:当前数表中间值大于等于x

  1. 即当目标值小于或等于中间元素,则将数表的上边界修改为中间元素,下边界不变,继续相同操作;
  2. 当目标值大于中间元素,则将数表的下边界修改为中间元素加一,上边界不变,继续相同操作;

通过以上步骤,一步一步将要查找的数组范围缩小,直至上边界不再大于下边界,此时两边界指向的元素就是要查找的元素。而对于这两种不同的比对方法我的理解是分别从左边和从右边分别逼近x。即:

条件arr[mid]>=x查找出来的是第一个最小的满足条件的数

条件arr[mid]<=x查找出来的是最后一个最大的满足条件的数

下面来看看两种实现:

1.第一种实现:

#include<stdio.h>

int main()
{
	int arr[10] = { 1,2,3,4,5,7,7,7,9,10 };
	int x = 0;
	scanf("%d", &x);
	int l = 0, r = 9;
	while (l < r)
	{
		int mid = l + r + 1 >> 1;
		if (arr[mid] <= x)
		{
			l = mid;
		}
		else
			r = mid - 1;
	}
	if(arr[l]==x)
		printf("%d ", l);
	return 0;
}

2.第二种实现:

#include<stdio.h>

int main()
{
	int arr[10] = { 1,2,3,4,5,7,7,7,9,10 };
	int x = 0;
	scanf("%d", &x);
	int l = 0, r = 9;
	while (l < r)
	{
		int mid = l + r >> 1;
		if (arr[mid] >= x)
		{
			r = mid;
		}
		else
			l = mid+1;		
	}
	if (arr[l] == x)
		printf("%d ", l);
	return 0;
}

按上面的说法,如果我们数表中有相同的数据,那么我们采用两种方式所得到的下标就不同:
arr[mid]>=x,那么得到的7的坐标是7;
arr[mid]<=x,那么得到的7的坐标是5
即:
arr[mid]>=x:

在这里插入图片描述

arr[mid]<=x:

优化:
既然我们数表中可能出现重复元素,那么我们就要针对这个元素,设计出一个方案,可以得到这个元素的起始位置和终止位置。为此我们自然而然想出一个结合上面两种思路的方法:输出端设计为两个数,分别是查找元素的起始坐标和末尾坐标,这样就能包含重复元素的情况。而判断性质我们也可以采用原来两个逼近的方式,这样我们就得到两个边界。
最后完整代码如下:

#include<stdio.h>

int main()
{
	int arr[10] = { 1,2,3,4,5,7,7,7,7,10 };
	int x = 0;
	int l = 0, r = 9;
	scanf("%d", &x);
	while (l < r)
	{
		int mid = l + r >> 1;
		if (arr[mid] >= x)  r = mid;
		else l = mid + 1;
	}
	if (arr[l] != x)
		printf("Fail\n");
	else
	{
		printf("%d ", l);
		int l = 0, r = 9;
		while (l < r)
		{
			int mid = l + r + 1 >> 1;
			if (arr[mid] <= x) l = mid;
			else r = mid - 1;
		}
		printf("%d", l);
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值