Java 算法篇-深入了解二分查找法

🔥博客主页: 小扳_-CSDN博客
❤感谢大家点赞👍收藏⭐评论✍
  

 

目录

        1.0 二分查找法的说明

        2.0 二分查找实现的多种版本

        2.1 二分查找的基础版本

        2.2 二分查找的改动版本

        2.3 二分查找的平衡版本

        2.4 二分查找的官方版本

        3.0 二分查找的应用


        1.0 二分查找法的说明

        二分查找法(Binary Search)是一种在有序数组有序列表中查找特定元素的搜索算法。其基本思想是将数组或列表分成两部分,取中间位置的元素进行比较,若该元素等于目标值,则查找成功若该元素大于目标值,则在左半部分继续查找若该元素小于目标值,则在右半部分继续查找。不断重复这个过程,直到找到目标值或查找范围缩小到只剩下一个元素为止。

        需要重点注意的是,使用二分查找的前提必须是数组是有序的或者列表是有序的。

        2.0 二分查找实现的多种版本

        基本来说可以分为基础版本和改动版本、平衡版、官方版本。

        2.1 二分查找的基础版本

        先来讲讲具体的实现吧,需要一个有序的数组 arr[] 或者有序列表,还有拿到需要查找的目标元素 int target

        需要定义一下三种变量:

        第一种,int left ;一开始记录着是最左边的元素的索引,即为 0.

        第二种,int right;一开始记录着是最右边的元素的索引,即为 array.length - 1

        第三种,int mid;记录着是中间的元素的索引,即为(left + right)>>> 1;

        接着先要用 arr[mid] 的元素与 target 进行对比,这时候就会有三种情况,分别做不同的处理,假如 if(arr[mid] < target ),中间的元素小于目标元素时,要对 left 进行 left = mid + 1处理,假如 if(arr[mid] > target ),中间的元素大于目标元素时,要对 right 进行 right = mid - 1处理,假如 if(arr[mid] = target ),这时候就找到了目标元素了,直接返回 mid ,因此这是一个循环的过程,不断缩小范围来寻找目标元素,这一切都需要满足 left <= right 这个条件。

具体代码实现如下:

public class BinarySearch {
    public static void main(String[] args) {
        int[] arr = {1,3,5,7,9,11};
        int target = 3;
        System.out.println(search(arr, target));
    }
    public static int search(int[] arr, int target){
        int left = 0;
        int right = arr.length - 1;
        while (left <= right){
            int mid = (left + right) >>> 1;
            if (arr[mid] < target){
                left = mid + 1;
            } else if (target < arr[mid]) {
                right = mid - 1;
            }else {
                return mid;
            }
        }
        return -1;
    }
}

运行结果如下:

        目标元素3的索引为1,补充一下,若没有找到的话,这里定义返回为 -1 。

        2.2 二分查找的改动版本

        这个版本在基础版本的基础上进行了三点改动:

        第一点;int right;一开始记录着是最右边的元素的索引,即为 array.length 。

        注意,在基础版本中是需要减1的,而这里直接取元素个数,当然我们都知道这个会出现越界情况,所以才会有第二点改动 。

        第二点;这一切都需要满足 left < right 这个条件。

        这基础版本中循环条件是需要 <= 的条件,这里就不需要了,来分析一下为什么呢?

        原因就在第一点,在 right 索引下的元素是不可取的,重点在<不可取>,仔细品味一下,无论right 在之后的循环中得到的所有索引都是不可取到的元素。

        第三点;假如 if(arr[mid] > target ),中间的元素大于目标元素时,要对 right 进行 right = mid 处理。

具体代码实现如下:

public class NewBinarySearch {
    public static void main(String[] args) {
        int[] arr = {1,3,5,7,9,11};
        int target = 3;
        System.out.println(search(arr, target));
    }
    public static int search(int[] arr, int target) {
        int left = 0;
        int right = arr.length;
        while (left < right) {
            int mid = (left + right) >>> 1;
            if (arr[mid] < target) {
                left = mid + 1;
            } else if (target < arr[mid]) {
                right = mid;
            } else {
                return mid;
            }
        }
        return -1;
    }
}

运行结果如下:

         2.3 二分查找的平衡版本

        相对比与第一、两种,这个版本的效率会更高一点。这种版本的思路就是将范围不断缩小为1,然后获取 left 索引下的元素,来判断是否等于目标元素。

具体代码如下:

public class NewBinarySearch {
    public static void main(String[] args) {
        int[] arr = {1,3,5,7,9,11};
        int target = 3;
        System.out.println(search(arr, target));
    }
    public static int search (int[] arr, int target){
        int left = 0;
        int right = arr.length;
        while (1 < right - left){
            int mid = (left + right) >>> 1;
            if (target < arr[mid]){
                right = mid;
            } else  {
                left = mid;
            }
        }
        if (arr[left] == target){
            return left;
        }else {
            return -1;
        }

    }
}

运行结果如下:

        2.4 二分查找的官方版本

直接来看原代码:

        来分析一下,从总体来看,官方的二分查找的实现跟第一种的基本版本是大致相同的,有一点跟基础版本的不同的是,就是返回值。在基础版本中,如果找不到就返回 -1,而这里返回的是 -(low + 1),接下来具体讲解一下。

        第一点low 代表的是插入点,这个值跟 left 的值是一样的。

        第二点,关于负数的说法,一般来说找不到的元素时,会返回负数。

具体代码的实现:

public class NewBinarySearch {

    public static void main(String[] args) {
        int[] arr = {1,3,5,7,9,11};
        int target = 2;
        System.out.println(search(arr, target));
    }
    public static int search(int[] arr, int target) {
        int left = 0;
        int right = arr.length - 1;
        while (left <= right) {
            int mid = (left + right) >>> 1;
            if (arr[mid] < target) {
                left = mid + 1;
            } else if (target < arr[mid]) {
                right = mid - 1;
            } else {
                return mid;
            }
        }
        return -(left + 1);
    }
}

运行结果如下:

        来算一下,我们知道 2 在数组中是不存在的,插入点为 1 ,则-(1+1)==  -2,验证了是符合的结果的。

 

        3.0 二分查找的应用

        给出下列数组 int[] arr {1,2,3,3,3,3,5,6,7} 要求返回目标元素3的起始位置与结束位置。

        实现的思路:先找起始位置,首先得先找到目标元素的索引,之后得往左边去找找结束位置也是同理,首先得先找到目标元素的索引,之后得往右边去找

代码如下:

public class NewBinarySearch {
    public static void main(String[] args) {
        int[] arr = {1,2,3,3,3,3,5,6,7};
        int target = 3;
        System.out.print(findLeft(arr, 3)+" ");
        System.out.println(findRight(arr, 3));
    }
    public static int findLeft(int[] arr,int target){
        int left = 0;
        int right = arr.length - 1;
        int sign = -1;
        while (left <= right){
            int mid = (left + right) >>> 1;

            if (arr[mid] < target){
                left = mid + 1;
            } else if (target < arr[mid]) {
                right = mid - 1;
            }else {
                sign = mid;
                right = mid - 1;
            }
        }
        return sign;
    }

    public static int findRight(int[] arr, int target){
        int left = 0;
        int right = arr.length - 1;
        int sign = -1;
        while (left <= right){
            int mid = (left + right) >>> 1;
            if (arr[mid] < target){
                left = mid + 1;
            } else if (target < arr[mid]) {
                right = mid - 1;
            }else {
                sign = mid;
                left = mid + 1;
            }
        }
        return sign;
    }
}

运行结果如下:

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Linux系统学习】系统编程开发工具编译器gcc/g++使用

个人主页点击直达&#xff1a;小白不是程序媛 Linux专栏&#xff1a;Linux系统学习 目录 前言 Linux系统下安装gcc和g gcc和g的不同 gcc/g的使用 gcc/g选项 预处理 头文件的展开 宏替换 注释的删除 条件的编译 编译 汇编 链接 系统库 库的分类 库的安装 库的…

[计算机提升] Windows系统软件:娱乐类

3.3 系统软件&#xff1a;娱乐类 3.3.1 Windows Media Player&#xff1a;dvdplay Windows Media Player是Windows操作系统自带的多媒体播放软件&#xff0c;用于播放和管理电脑中的音频和视频文件。它提供了以下功能&#xff1a; 播放音频和视频文件&#xff1a;Windows Med…

基于ThinkPHP+MySQL实现的通用的PHP网站后台管理系统

caozha-admin 后台管理框架 1.8.3 caozha-admin是一个通用的PHP网站后台管理框架&#xff0c;基于开源的ThinkPHP开发&#xff0c;特点&#xff1a;易上手&#xff0c;零门槛&#xff0c;界面清爽极简&#xff0c;极便于二次开发。 基础功能 1、系统设置 2、管理员管理 3、…

搭建ELK+Filebead+zookeeper+kafka实验

一、ELKFilebeatkafkazookeeper架构 架构图分别演示 第一层&#xff1a;数据采集层 数据采集层位于最左边的业务服务集群上&#xff0c;在每个业务服务器上面安装了filebead做日志收集&#xff0c;然后把采集到的原始日志发送到kafkazookeeper集群上。 第二层&#xff1a;消…

vue3中,使用html2canvas截图包含视频、图片、文字的区域

需求&#xff1a;将页面中指定区域进行截图&#xff0c;区域中包含了图片、文字、视频。 第一步&#xff0c;先安装 npm install html2canvas第二步&#xff0c;在页面引入&#xff1a; import html2canvas from html2canvas;第三步&#xff0c;页面使用&#xff1a; 1&…

SpringCloudGateway--过滤器(自定义filter)

目录 一、概览 二、通过GatewayFilter实现 三、继承AbstractGatewayFilterFactory 一、概览 当使用Spring Cloud Gateway构建API网关时&#xff0c;可以利用Spring Cloud Gateway提供的内置过滤器&#xff08;filter&#xff09;来实现对请求的处理和响应的处理。过滤器可以…

TiDB 企业版全新升级,平凯数据库核心特性全解读

作为 TiDB 企业版的全新升级&#xff0c;平凯数据库一经推出便广受媒体及用户关注。 近日&#xff0c;平凯星辰首席科学家丁岩在“平凯数据库全解读”活动中&#xff0c;首次详细介绍了平凯数据库的核心能力。 本文为丁岩演讲实录全文&#xff0c;为方便阅读&#xff0c;已做部…

物联网AI MicroPython传感器学习 之 QMC5883指南针罗盘传感器

学物联网&#xff0c;来万物简单IoT物联网&#xff01;&#xff01; 一、产品简介 QMC5883是一款表面贴装的集成了信号处理电路的三轴磁性传感器&#xff0c;应用场景主要包括罗盘、导航、无人机、机器人和手持设备等一些高精度的场合。 引脚定义 VCC&#xff1a;3V3&#…

自定义的卷积神经网络模型CNN,对图片进行分类并使用图片进行测试模型-适合入门,从模型到训练再到测试,开源项目

自定义的卷积神经网络模型CNN&#xff0c;对图片进行分类并使用图片进行测试模型-适合入门&#xff0c;从模型到训练再到测试&#xff1a;开源项目 开源项目完整代码及基础教程&#xff1a; https://mbd.pub/o/bread/ZZWclp5x CNN模型&#xff1a; 1.导入必要的库和模块&…

数据结构与算法:使用数组模拟环形队列Java版

文章目录 如何使用数组模拟队列环形队列逻辑分析自己写的听课笔记实现代码部分方法说明 如何使用数组模拟队列 不知道如何使用数组模拟队列的可以看上一篇文章 使用数组模拟队列点击跳转 环形队列逻辑分析 自己写的听课笔记 实现代码 package com.haimeng.queue;import java…

uniapp-自定义表格,右边操作栏固定

uniapp-自定义表格&#xff0c;右边操作栏固定 在网上找了一些&#xff0c;没找到特别合适的&#xff0c;收集了一下其他人的思路&#xff0c;基本都是让左边可以滚动&#xff0c;右边定位&#xff0c;自己也尝试写了一下&#xff0c;有点样式上的小bug&#xff0c;还在尝试修…

多线程锁的升级原理是什么

在 Java 中&#xff0c;锁共有 4 种状态&#xff0c;级别从低到高依次为&#xff1a;无状态锁&#xff0c;偏向锁&#xff0c;轻量级锁和重量级锁状态&#xff0c;这几个状态会随着竞争情况逐渐升级。锁可以升级但不能降级。 多线程锁锁升级过程 如下图所示 多线程锁的升级过程…

在NISQ小型计算机上执行大型并行量子计算的可能性

简介 Steve White提出了密度矩阵重整化群&#xff08;DMRG&#xff09;的基本思想&#xff0c;即纠缠是一种有价值的资源&#xff0c;可以用来精确或近似地描述大量子系统。后来&#xff0c;这一思想被理解为优化矩阵积状态&#xff08;MPS&#xff09;的算法&#xff0c;支持…

Android开发笔记(三)—Activity篇

活动组件Activity 启动和结束生命周期启动模式信息传递Intent显式Intent隐式Intent 向下一个Activity发送数据向上一个Activity返回数据 附加信息利用资源文件配置字符串利用元数据传递配置信息给应用页面注册快捷方式 启动和结束 &#xff08;1&#xff09;从当前页面跳到新页…

[idea]关于idea开发乱码的配置

在JAVA开发中&#xff0c;一般统一设置为UTF-8的编码&#xff0c;包括但不限于开发工具、日志架构、虚拟机、文件编码等。常见配置如下&#xff1a; 1、IDEA工具 在idea64.exe.vmoptions、idea.exe.vmoptions中添加&#xff1a; -Dfile.encodingUTF-8 2、JAVA 运行在window…

python科研绘图:条形图

条形图&#xff08;bar chart&#xff09;是一种以条形或柱状排列数据的图形表示形式&#xff0c;可以显示各项目之间的比较。它通常用于展示不同类别的数据&#xff0c;例如在分类问题中的不同类别、不同产品或不同年份的销售数据等。 条形图中的每个条形代表一个类别或一个数…

区块链与教育:颠覆传统,引领未来

区块链与教育&#xff1a;颠覆传统&#xff0c;引领未来 摘要&#xff1a;本文将探讨区块链技术在教育领域的应用及其潜在影响。通过介绍区块链技术的基本原理、教育领域的现状&#xff0c;以及区块链技术在教育中的实际应用案例&#xff0c;我们将展望一个去中心化、安全可信…

软件测试面试高频30道面试题

如果哪个测试经理在看我的文章&#xff0c;希望对面试者要微笑&#xff0c;不然面试结束&#xff0c;出门之后就一万个草泥马奔腾而过&#xff0c;其实面试者并不是希望你给他们什么&#xff0c;而是一种尊重&#xff0c;平等的谈话&#xff0c;不要高高在上感觉自己超牛逼一样…

【星海出品】VUE(一)

Windows安装nvm控制器 Windows里找都PowerShell。右击点击管理员运行。 1.安装choco Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString(https://chocolatey.org/install.ps1))2.安装NVM choco install nvm 3.查看可…

【HeidiSql_01】python在heidisql当中创建新表的注意事项

python在heidisql当中创建新表的注意事项 假设你已经在python当中弄好了所有的结果&#xff0c;并且保存在df_all这个dataframe当中&#xff0c;然后要将其导入数据库当中并创建一张新的表进行保存。 # 构建数据库连接,将merged_df写回数据库 from sqlalchemy import create_e…
最新文章