首页 > 其他分享 >二分查找(数组的练习)

二分查找(数组的练习)

时间:2024-07-23 20:55:16浏览次数:17  
标签:二分 key mid high 查找 low 数组

一、什么是二分查找

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

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

二、算法思想

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的方法,不懂的看这篇文章:http://t.csdnimg.cn/wt5LY;不懂while里EOF用法的看这篇文章的“scanf的返回值”部分:http://t.csdnimg.cn/80wMT

#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,两者结果并不一样。

标签:二分,key,mid,high,查找,low,数组
From: https://blog.csdn.net/2401_86272648/article/details/140643984

相关文章

  • day8 字符数组
    字符数组用来存放字符数据的数组叫字符数组。字符数组中每一个元素存放一个字符。字符数组主要用于处理c中字符串的使用。字符串:“helloworld”用双引号引用起来的就是字符串,在双引号中,字符串中的字符不可更改。字符串在内存当中按照先后次序排列起来c语言中,规定了字符串......
  • 字符串数组
    一、二分查找法将一个有序的数列取中值,判断数在哪一段,每次筛选原来的一半,重复多次二、字符串数组(容器,用来存放字符)1.初始化内容:chars[100]=“hello”(字符串常量)字符串结束标志:\0(空字符)单一性、连续性、有序性2.输出字符串puts(s)=puts(&s[0])3.输入字符串scanf......
  • 数组和指针的关系,const修饰指针
     数组和指针的关系 const修饰指针总结:const修饰谁谁就不能变      const修饰*( const在* 前)          不能改变*p的值,可以改变p的指向     const修饰p(const在*后)          不能改变p的指向,可以改......
  • SA & SAM 后缀数组 & 后缀自动机
    终于来到大名鼎鼎的后缀结构了,后缀结果可以解决许多子串问题。后缀结果是字符串经常考察的点,需要重点学习。SA后缀排序,是指这个对字符串\(s\)的每一个后缀字符串进行排序,通过处理每个后缀的前缀来解决子串问题。\(SA\):排名为\(i\)对应原字符串下标,\(rk\):下标为\(i\)的后缀排名。......
  • 字符数组啊啊啊啊
    字符数组的定义字符数组是专门用来存放字符串的容器字符串“”,用双引号引起来且按顺序的叫字符串字符串的结束标志是‘\0’表示方式最简为s[100]=“helloworld”;输出字符串函数:int puts(constchar*s)括号内直接填写字符数组的数组名,puts(s)输入字符串函数:char*gets......
  • 一维数组啊啊啊啊啊啊
    一维数组的定义结构:类型说明符数组名[常量表达式];类型说明符可以是已有的数据类型(唯独不能是void)一维数组元素的使用[]是下标,下标运算符在定义数组时的[]不是下标运算符,是类型说明符,为了说明n为数组数组的数组名代表数组的首元素的地址地址为一个地址值常量不能作为左......
  • 代码随想录算法训练营Day5、6 | Leetcode 242 有效字母的异位词 Leetcode 349 两个数
    前言因为昨天休息所以把两天合并成一天来写,昨天把上周的题又重写了一遍,发现一些细节还是要注意。今天的题目都是查找,也涉及到了最近正在学的STL。Leetcode242有效字母的异位词 题目链接:https://leetcode.cn/problems/valid-anagram/description/代码随想录题解:代码随想......
  • KMP算法中next数组以及nextval的求解(简单,通俗易懂版)
    以一个题为例:计算上图中next[j]以及nextval[j]的值。【本文中j的下标从1开始。】最长公共前后缀:···前缀:不包含最后一个字符的所有以第一个字符开头的连续子串。···后缀:不包含第一个字符的所有以最后一个字符结尾的连续子串。先看next[j],(1)j的下标......
  • React中函数组件中闭包陷阱如何产生,如何解决?
    在什么情况下会产生闭包陷阱?在React中,当使用useState和useEffect以及useCallback时,我们必须得注意闭包陷阱,避免出现一些意外的行为什么是闭包陷阱?闭包是指一个函数可以访问其词法作用域之外的变量。闭包主要发生的集中情况?在useState中的闭包陷阱在useEffect中的闭......
  • 力扣209. 长度最小的子数组C++、窗口写法
    给定一个含有 n 个正整数的数组和一个正整数 target 。找出该数组中满足其总和大于等于 target 的长度最小的 子数组 [numsl,numsl+1,...,numsr-1,numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。示例1:输入:target=7,nums=[2,3,1,2,4,3]......