【C语言】【数据结构】二分查找(数组的练习)

目录

一、什么是二分查找

二、算法思想

2.1、概述

2.2、举例

(1)查找3(数组里面存在的数)

(2)查找12(数组里面不存在的数)

三、代码实现

四、计算mid公式的优化


一、什么是二分查找

二分查找(又叫折半查找)是一种查找算法,它能使查找的速度更快 ,但要求查找的序列必须有序

如果我们按顺序在一个序列中查找一个数,当这个数在靠前的位置,查找的速度还好;那么当这个数在很靠后的位置呢?甚至是一个很长的数组,要查找的数是最后一个元素,这种情况下查找的速度就很慢了。因此我们需要用更优的二分查找算法。

二、算法思想

2.1、概述

记录数组的三个位置:low、high、mid分别记录当前查找的数组子集的起始位置、结束位置、中间位置。当前数组子集的mid = (low + high) / 2,注意:C语言中整型数相除,结果会舍去小数部分。

每次将要查找的数key与mid位置的数比较:如果key大于mid位置的数,说明key是在数组右半子集的范围里,那么更新子集的范围,low更新为mid+1;如果key小于mid位置的数,说明key是在数组左半子集的范围里,那么更新子集的范围,high更新为mid - 1。

重复上述的过程,直到查找到key,或者low大于high(key没在数组中)结束。

2.2、举例

有序数组如下,并标记三个位置:

(1)查找3(数组里面存在的数)

第一趟:3比5小

第二趟:3比2大

第三趟:3等于mid位置的数3,查找成功。

(2)查找12(数组里面不存在的数)

第一趟:12比5大

第二趟:12比8大

第三趟:12比9大

第四趟:12比10大

low比high大,结束,查找失败。

三、代码实现

代码中使用sizeof计算len的方法,不懂的看这篇文章的"sizeof计算数组的长度"这一部分:http://t.csdnimg.cn/wt5LY;不懂while里EOF用法的看这篇文章的"scanf的返回值"部分:http://t.csdnimg.cn/80wMT

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>

int main() {

	int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	int len = sizeof(arr) / sizeof(arr[0]); //数组的长度
	int low, high, mid, key;

	while(scanf("%d", &key) != EOF){ // 控制查找多次
		low = 0;
		high = len - 1;
		while (low <= high) {
			mid = (low + high) / 2;
			if (key > arr[mid])
				low = mid + 1;
			else if (key < arr[mid])
				high = mid - 1;
			else {
				printf("查找成功,在下标%d处\n", mid);
				break;
			}
		}
		if (low > high)
			printf("查找失败\n");
	}

	return 0;
}

运行结果:

四、计算mid公式的优化

当数组很长时,low、high很可能是一个很大的数,这时候会出现一些问题。用Everthing软件查看一下<limits.h>头文件里的INT_MAX的值为2147483647,假如把low和high都初始化为2147483646,看看有什么结果:

会发现结果跟我们预期的不一样,这是因为数值超过了int类型的长度,发生了溢出(暂且不深入了解是什么原理)。所以需要优化mid的计算方法,如下图所示:

我们可以把长的与短的做差,再将这个差除以2,最后将这一半补到短的上面,就可以避免加法造成溢出了。因此可以将mid计算公式优化为mid = low + (high - low) / 2。再运行看看:

得到了正确的结果。

有人会想,为什么不直接用mid = low / 2 + high / 2呢?因为整除是会舍去小数部分的,两次分别做除法,舍去的小数部分可能更多,误差就更大了。比如3 / 2 + 5 / 2 = 3 ;而(3 + 5) / 2 = 4,两者结果并不一样。

相关推荐
祖力557 小时前
数据结构的基本概念与单向链表(链表数据类型构造、创建、头插、尾插、头删、尾删)
数据结构·链表
大明者省9 小时前
WSL2 Ubuntu22.04 GPU训练环境配置指南
人工智能·算法·计算机视觉
WWJA王文举9 小时前
I²C通信完整流程详解:START、地址、ACK、数据、Repeated START和STOP一次讲透
c语言·开发语言
白狐_79810 小时前
408数据结构第8章:排序②——性质对比秒杀、场景选择与外部排序
java·数据结构·算法
zander25811 小时前
LeetCode 84:柱状图中的最大矩形——单调栈如何确定左右边界
java·数据结构·算法
Shell运维手记11 小时前
Linux 常用基础命令学习笔记
linux·运维·笔记·学习·算法·github
qq_4480111611 小时前
C语言中的动态内存分配
c语言·开发语言·php
杨航 AI11 小时前
O(n log n):线性对数原理拆解 这个是排序算法的黄金复杂度之一。
算法·排序算法
船厂电气自动化ai大模型12 小时前
AI大模型与数学 第32课 函数凹凸性与二阶导数:拐点求解、凹凸区间计算(10道二阶导数计算题)
数据结构·人工智能·python·深度学习·算法
动词ing12 小时前
【学习笔记】C语言(数组指针与指针数组+字符数组+函数+参数传递+字符串作为形参+递归函数+指针函数+回调函数+结构体嵌套+内存动态分配函数)
c语言·笔记·学习