一篇文章彻底搞懂折半查找法[二分查找法]算法~

news2024/11/22 23:08:33

算法实现的要求:

折半查找法又称为二分查找法,这种方法对待查找的列表有两个要求:

1:必须采用顺序存储结构
2:必须按关键字大小有序排列

算法思想:

将表中间位置记录的关键字与查找关键字进行比较如果两者相等,则查找成功,否则利用中间位置记录将表分成前后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表

重复上述查找过程,直到找到满足条件的记录,则查找成功,或直到子表不存在为止,则查找不成功

使用java实现该算法:

算法实现方法:

1:前提要求:有已排序数组A[因为在查找的过程中是根据下标进行的]

2:定义左边界L,右边R,确定搜索范围,循环执行二分查找

3:获取中间索引M=(L+R)/2,如果是小数,一般默认向下取整

4:中间索引的值A[M]与带搜索的值T进行比较
A[M]==T,返回中间索引
A[M]>T,中间值右侧的其他元素都大于T,无需比较,中间索引左边去找,M-1,设置为右边界,重新查找
A[M]<T,中间值左侧的其他元素都小于T,无需比较,中间索引右边去找,M+1设置为左边界,重新查找

5:当L>R时,表示没有找到,应结束循环

代码如下所示:

package bin_find;

import java.util.Scanner;

public class bin_find {
    public static void main(String[] args) {
        int arr[] = {4, 10, 18, 23, 45, 68, 199};
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入你要查找的数:");
        int x = scanner.nextInt();
        int result= bin_research(arr,x);
        if(result!=-1){
            System.out.println("你要查找的数已找到,它是数组的第"+(result+1)+"个元素");
        }
        else{
            System.out.println("你要查找的数不存在");
        }
    }

    public static int bin_research(int arr[], int x) {
        int L = 0;
        int R = arr.length - 1;
        while(L<=R) {
        //不要写到循环外面了,因为每查找一次,中间索引的位置也需要变化
            int M = (L + R) / 2;
            if (x > arr[M]) {
                L = M+1;
            } else if (x < arr[M]) {
                R = M - 1;
            } else if (x == arr[M]) {
                return M;
            }
        }
        return -1;
    }
}

输出:

请输入你要查找的数:
23
你要查找的数已找到,它是数组的第4个元素

整数溢出现象:

package bin_find;

public class bin_find2 {
    public static void main(String[] args) {
        int l=0;
        int r=Integer.MAX_VALUE-1;
        int m=(l+r)/2;
        //当要查找的数在左子表时:
        System.out.println(m);
        //当要查找的数在右子表时:发生整数溢出现象
        l=m+1;
        m=(l+r)/2;
        System.out.println(m);
    }
}

输出:

1073741823
-536870913

之所以会出现负数的原因:是因为在计算机中,是根据二进制进行运算的,逢二进一,由于最高位表示符号位,当它为1时,该数即为负数!

对该过程不熟悉的小伙伴,可以去看我写的这篇文章

解决整数溢出问题:

上述代码中产生溢出的原因是由于:当要查找的数在右子表时,此时:r最初为整数的最大值-1不变,而l的值增大到了r/2的大小,因此即使他两相加除2,在计算机中,是根据二进制进行运算的,逢二进一,由于最高位表示符号位,当它为1时,该数即为负数,那么解决溢出的核心就是改变m的值,但所谓的改变,并不是将m的值真正的改变,而是通过变换表达式等等,去调整m的大小

方法1:通过调整数学表达式

方法如下:

在这里插入图片描述

代码如下:

package bin_find;

public class bin_find2 {
    public static void main(String[] args) {
        int l=0;
        int r=Integer.MAX_VALUE-1;
        int m=l+(r-l)/2;
        //当要查找的数在左子表时:
        System.out.println(m);
        //当要查找的数在右子表时:
        l=m+1;
        m=l+(r-l)/2;
        System.out.println(m);
    }
}

输出:

1073741823
1610612735

方法2:通过>>>运算符

>>>表示无符号右移运算符也叫逻辑右移,即若该数为正,则高位补0,而若该数为负数,则右移后高位同样补0,移动的是二进制位,但他们的操作数必须是整数,[当被操作的数是整数时]右移一位有除二的效果,因此对于上述溢出现象,右移一位既能够避免最高位[符号位]为1,导致该数为负数的现象,而且正好借用它右移一位有除二的效果,还简化了数学表达式;

修改如下:

package bin_find;

public class bin_find2 {
    public static void main(String[] args) {
        int l=0;
        int r=Integer.MAX_VALUE-1;
        int m=(r+l)>>>1;
        //当要查找的数在左子表时:
        System.out.println(m);
        //当要查找的数在右子表时:
        l=m+1;
        m=l+(r-l)>>>1;
        System.out.println(m);
    }
}

输出:

1073741823
1073741823

对于上述两种做法均可以解决整数溢出问题,不过我们更加推荐第二种,因为它的效率比较高!

练习题:

有一个有序表为 1,5,8,11,19,22,31,35,4045,89,50 当分查找值为48的结点时,查找成功需要比较的次数
[来源于:京东实习生招聘]

答案为:4次

这里需要强调的点就是:当子表的元素个数为偶数时,如果题目没有强调,那么我们默认选择靠左边的元素为中间数

使用二分法在序列 1,4,6,7,15,33,39,50,64,78,75,81,89,96 中查找元素81 时,需要经过()比较
[来源于:美团点评校招]

答案为:4次

在拥有128个元素的数组中二分查找一个数,需要比较的次数最多不超过多少次 [来源于:北京易道博识社招]

答案为:7次

方法1:
上述题目相当于为2^n=128,n的值为多少?

方法2:
使用128一直不断的除2,直到变为1,只需要计算除2的次数即可

方法3:
使用计算器,问题转变为log2^128,不过需要知道该计算机是以多少为底,下图为Windows10操作系统的计算器,以10为底

在这里插入图片描述

运算结果是整数,则该整数即为最终结果

运算结果是小数,则舍去小数部分,整数加一为最终结果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/165677.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

性能测试时那些「难以启齿」的问题-CPU相关

NO.1 为什么cpu使用率可以>100%? 小白的我在进行压测的时候&#xff0c;查看服务的cpu总使用率如下&#xff0c;总使用率会超过100%&#xff0c;这个数据是怎么来的呢&#xff0c;为什么会有大于100%的情况呢&#xff1f; 作为小白的我刚开始觉得这个问题应该很基础&#x…

Go语言实现猜数字小游戏

目录 前言 一、设计思路 二、代码编写 2.1 产生随机数 2.2 用户输入数据 2.3 核心代码 三、 全部代码 四、效果图 总结 前言 最近在学习go语言&#xff0c;刚刚学完go语言的基础语法。编写了一个猜数字的小游戏来练习循环、分支语句、变量定义、输入输出等基础的go语…

4、变量与常量

目录 一、标识符和关键字 1.标识符 2.关键字 二、声明变量 三、声明常量 四、变量的有效范围 1. 成员变量 2. 局部变量 一、标识符和关键字 1.标识符 Java语言规定标识符由任意顺序的字母、下画线&#xff08;_&#xff09;、美元符号&#xff08;$&#xff09;和数字…

【数据结构】手撕八大排序算法

作者&#xff1a;一个喜欢猫咪的的程序员 专栏&#xff1a;《数据结构》 喜欢的话&#xff1a;世间因为少年的挺身而出&#xff0c;而更加瑰丽。 ——《人民日报》 目录 1.排序的概念&#xff1a; 2.八大排序的思路及其细节 2.1直接插入排序 …

适合编程初学者的开源项目:小游戏2048(安卓Compose版)

目标 为编程初学者打造入门学习项目&#xff0c;使用各种主流编程语言来实现。 2048游戏规则 一共16个单元格&#xff0c;初始时由2或者4构成。 1、手指向一个方向滑动&#xff0c;所有格子会向那个方向运动。 2、相同数字的两个格子&#xff0c;相遇时数字会相加。 3、每次…

SpringMVC面试题

概述 什么是Spring MVC&#xff1f;简单介绍下你对Spring MVC的理解&#xff1f; Spring MVC是一个基于Java的实现了MVC设计模式的请求驱动类型的轻量级Web框架&#xff0c;通过把模型-视图-控制器分离&#xff0c;将web层进行职责解耦&#xff0c;把复杂的web应用分成逻辑清…

如何在Linux上搭建C++开发环境

工欲善其事&#xff0c;必先利其器&#xff01;我们要在Linux上开发C程序&#xff0c;就要先搭建好它的开发环境。 搭建环境步骤安装Linux安装开发工具写一个demo在项目根目录创建一个构建脚本build.sh使用CodeLite IDE打开项目安装Linux Linux的发行版本很多&#xff0c;萝卜…

测试开发——测试分类

目录 一、 有关测试用例的回顾 二、 测试用例的划分 1、 按照测试对象来划分 可靠性测试 容错性测试 内存泄漏测试 弱网测试 2、按照是否查看代码划分 3、按照开发阶段划分 一、 有关测试用例的回顾 万能测试用例设计公式 如何根据需求去设计测试用例&#xff1f; …

计算机视觉OpenCv学习系列:第三部分、滚动条操作

第三部分、滚动条操作第一节、滚动条操作1.事件响应函数&#xff08;1&#xff09;UI组件时间响应过程&#xff08;2&#xff09;事件响应函数&#xff08;3&#xff09;创建窗口函数&#xff08;4&#xff09;调整图像亮度2.滚动条操作3.代码练习与测试学习参考第一节、滚动条…

Python 协程学习有点难度?这篇文字值得你去收藏

Python 协程在基础学习阶段&#xff0c;属于有难度的知识点&#xff0c;建议大家在学习的时候&#xff0c;一定要反复练习。 Python 中的协程是一种用户态的轻量级线程。它与普通的线程不同&#xff0c;普通线程是由操作系统调度的&#xff0c;而协程是由程序自己调度的。因此&…

【ESP 保姆级教程】玩转emqx篇③ ——认证安全之使用内置数据库(Mnesia)的密码认证

忘记过去&#xff0c;超越自己 ❤️ 博客主页 单片机菜鸟哥&#xff0c;一个野生非专业硬件IOT爱好者 ❤️❤️ 本篇创建记录 2023-01-15 ❤️❤️ 本篇更新记录 2022-01-15 ❤️&#x1f389; 欢迎关注 &#x1f50e;点赞 &#x1f44d;收藏 ⭐️留言&#x1f4dd;&#x1f64…

Transformer模型详解相关了解

文章目录Transformer模型详解1.前言1.1 Transformer 整体结构1.2 Transformer 的工作流程2. Transformer 的输入2.1 单词 Embedding2.2 位置 Embedding3. Self-Attention&#xff08;自注意力机制&#xff09;3.1 Self-Attention 结构3.2 Q, K, V 的计算3.3 Self-Attention 的输…

《神经网络与深度学习》 邱希鹏 学习笔记(一)

一、机器学习的基本要素 机器学习的基本要素: 模型 学习准则 优化算法 其中模型分为线性和非线性。学习准则有用损失函数来评价模型的好坏&#xff0c;还有经验风险最小化准则&#xff0c;大概意思就是在平均损失函数中获得最小的损失函数&#xff0c;但是因为样本可能很小&…

Goodbye 2022,Welcome 2023 | 锁定 2023

引言又是一年春来到&#xff0c;新年应比旧年好。旧岁已辞&#xff0c;新年已到&#xff0c;新旧更迭之际&#xff0c;真想剪个头发换身行头&#xff0c;就能重新出发。但终究是要回头看看啊&#xff0c;那一路而来的荆棘与芬芳&#xff0c;才是成长的印记啊。那就回拨记忆&…

和涤生大数据的故事

1自我介绍 大家好&#xff0c;我是泰罗奥特曼&#xff0c;毕业于东北的一所不知名一本大学&#xff0c;学校在一个小城市里面&#xff0c;最热闹的地方是一个四层楼的商城&#xff0c;专业是信息管理与信息系统&#xff0c;由于是调剂的&#xff0c;所以我也不知道这个专业是干…

一篇文章带你学完JavaScript基础知识,超全的JavaScript知识点总结

目录 内置函数 alert警告框 promopt提示框 console控制台 字面量 数字型 字符串型 变量 声明与赋值 类型检测 类型转换 比较运算符 逻辑运算符 条件句 if else switch break,continue while 赋值运算符 函数 关键字形式函数 变量认知 作用域 表达式…

什么样的故障让阿里云换了总裁?

&#x1f4e3;&#x1f4e3;&#x1f4e3;&#x1f4e3;&#x1f4e3;&#x1f4e3;&#x1f4e3; &#x1f38d;大家好&#xff0c;我是慕枫 &#x1f38d;前阿里巴巴高级工程师&#xff0c;InfoQ签约作者、阿里云专家博主&#xff0c;一直致力于用大白话讲解技术知识 &#x…

SpringBoot数据访问Redis

目录 前言 1、Redis自动配置 2、RedisTemplate与Lettuce 3、切换至jedis 前言 Redis 是一个开源&#xff08;BSD许可&#xff09;的&#xff0c;内存中的数据结构存储系统&#xff0c;它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构&#xff0c;如 字符串…

基于贝叶斯算法的邮件过滤管理系统的设计和实现(Vue+SpringBoot)

作者主页&#xff1a;Designer 小郑 作者简介&#xff1a;Java全栈软件工程师一枚&#xff0c;来自浙江宁波&#xff0c;负责开发管理公司OA项目&#xff0c;专注软件前后端开发&#xff08;Vue、SpringBoot和微信小程序&#xff09;、系统定制、远程技术指导。CSDN学院、蓝桥云…

Java对象引用级别

为了使程序能更灵活地控制对象生命周期&#xff0c;从 JDK1.2 版本开始&#xff0c;JDK把对象的引用级别由高到低分为强引用、软引用、弱引用、虚引用四种级别。 强引用 StrongReference 强引用是我们最常见的对象&#xff0c;它属于不可回收资源&#xff0c;垃圾回收器&…