二分查找(折半查找)算法教学

二分查找(折半查找)算法教学

使用二分查找的好处

在这里我用日常生活举例.比如询问一台电脑的价格,它的价格区间在**(1, 10000)**之间.我们的第一反映肯定是询问价格是超于5000还是低于5000,这样可以排除一半的错误答案,再以此类推,不断砍半.最终会以小于14次折半找到正确答案(2^14^=16384).比1元,2元,3元这种每次加一的询问不知道好多少(现实应该不会遇到这种人).

二分查找在代码中的逻辑(运算过程)

在数组中实现二分查找必须要能满足一个条件--数组是有序数组 ,像我们的价格一样,从1到10000之间是有序的. 我们假设有这样一个数组 像在日常中询问价格一样,我们需要知道它的价格区间,在这里体现为下标的区间.最左边的下标是0 ,那么右边的下标怎么计算呢?一个个算不成? 肯定不是,这里我给大家推荐一种方法:函数sizeof

sizeof(arr)算出的是数组的大小,也就是一共有多少个字节.int类型是4个字节,这个数组10个元素,那就是40个字节.用数组的总大小40个字节除以数组一个元素的大小4个字节就能知道数组的元素为10个 这下子我们也就知道了最右边的下标为10-1=9(下标是由0开始的,而元素个数是由1开始的). 然后跟上面的举例一样,我们要知道它的中间值,也就是 然后我们每次要将我们要查找的数字k(假设k=6),跟数组的中间值arrmid进行比较.当mid=4时,arrmid=5,5<6.这个时候我们发现一个比较是无法解决问题的,我们要添加循环.在我们进行第二轮查找时,因为arrmid<k,所以我们要改变left的值,将left改为mid+1.right不变. 若arrmid>k,我们要改变right的值,将right改为mid-1.left不变. 遇到arrmid=k,跳出循环. 即`

c 复制代码
    if (k < arr[mid])
		right = mid - 1;
	else if (k > arr[mid])
		left = mid + 1;
	else
		break;

因为在循环中mid的值一直会改变,所以将mid = (left + right) / 2写到循环里面. 循环的判断条件是left<=right.(要判断物品的价格一定要有个区间,就算这个区间只有一个数)

二分查找实现在主函数内

c 复制代码
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main() {
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	//            0,1,2,3,4,5,6,7,8,9
	int sz = sizeof(arr) / sizeof(arr[0]);
	int left = 0, right = sz - 1;
	
	int k = 0, mid =0;
	scanf("%d", &k);
	while (left <= right) {
		mid = (left + right) / 2;
		if (k < arr[mid])
			right = mid - 1;
		else if (k > arr[mid])
			left = mid + 1;
		else
			break;
	}
	if (left <= right)
		printf("找到了,下标是%d\n", mid);
	else
		printf("找不到\n");
	return 0;
}

在自定义函数实现二分查找函数

c 复制代码
int find(int arr[], int sz, int k) {
	int left = 0, right = sz - 1,mid=0;
	while (left <= right) {
		mid = (left + right) / 2;
		if (k < arr[mid])
			right = mid - 1;
		else if (k > arr[mid])
			left = mid + 1;
		else
			return mid;
	}
	return -1;
}
int main() {
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	//            0,1,2,3,4,5,6,7,8,9
	int sz = sizeof(arr) / sizeof(arr[0]);
	
	
	int k = 0;
	scanf("%d", &k);

	int ret = find(arr, sz, k);
	if (ret==-1)
		printf("找不到\n");
	else
		printf("找到了,下标是%d\n", ret);
	return 0;
}
c 复制代码
在这里插入代码片

##改进和易错之处 与我们要寻找的元素k相互比较的是数组中的元素,不是中间值mid 2.mid在每次循环中的改变可以写成

c 复制代码
mid = left + (right-left)/2;

这样修改的会让我们的mid更加"耐打".*当我们的left和right都大于int类型最大值的一半或者两者相加大于大于最大值时会导致栈溢出,使得到的mid数据缺失.*这样子可以修改避免二者直接相加.

复制代码
相关推荐
Jerry5 分钟前
LeetCode 28. 找出字符串中第一个匹配项的下标
算法
Jerry2 小时前
LeetCode 459. 重复的子字符串
算法
海石5 小时前
1500分的题目,确实有实力,不过还是我略胜一筹
算法·leetcode
海石5 小时前
【记忆化搜索】条条大路通AC,走好适合你的那一条,走到后再考虑走得快
算法·leetcode
Jerry7 小时前
LeetCode 151. 反转字符串中的单词
算法
a1117769 小时前
LM 算法迭代过程动画演示(SLAM)
算法
头茬韭菜9 小时前
Context 的生死抉择:四层压缩、截断算法与 Session Memory
算法·ai
Jerry9 小时前
LeetCode 541. 反转字符串 II
算法
Jerry10 小时前
LeetCode 344. 反转字符串
算法
搞科研的小刘选手10 小时前
【香港大学主办&IEEE出版】第六届计算机视觉、应用与算法国际学术会议(CVAA 2026)
算法·计算机视觉·应用·学术会议