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

news2025/1/23 11:28:33

🔥博客主页: 小扳_-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.coloradmin.cn/o/1164094.html

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

相关文章

OpenCV的绘图工具(rectangle、circle、line、polylines、putText)常用方法简介【C++的OpenCV 第十五课】

&#x1f389;&#x1f389;&#x1f389; 欢迎各位来到小白 p i a o 的学习空间&#xff01; \color{red}{欢迎各位来到小白piao的学习空间&#xff01;} 欢迎各位来到小白piao的学习空间&#xff01;&#x1f389;&#x1f389;&#x1f389; &#x1f496; C\Python所有的入…

项目管理之如何分配项目工作任务

项目资源配置技术是项目管理中至关重要的环节&#xff0c;它直接影响到项目的效率、质量以及最终的成果。本文将介绍项目资源配置技术&#xff0c;包括小组团队主管配置、保持团队规模小型化、保持团队人员能力均衡、为保证团队速度及质量&#xff0c;团队资源复用数量限制以及…

智能工厂架构

引:https://www.bilibili.com/video/BV1Vs4y167Kx/?spm_id_from=333.788&vd_source=297c866c71fa77b161812ad631ea2c25 智能工厂框架 智能工厂五层系统框架 MES 数据共享 <

Leetcode—2103.环和杆【简单】

2023每日刷题&#xff08;十六&#xff09; Leetcode—2103.环和杆 实现代码 struct ring{int r;int g;int b; }sticks[10]{0};int countPoints(char * rings){char *p rings;int i;for(i 0; i < 10; i) {sticks[i].r 0;sticks[i].g 0;sticks[i].b 0;}while(*p ! \0)…

大厂面试题-为什么Netty线程池默认大小为CPU核数的2倍

目录 1、分析原因 2、如何衡量性能指标 3、总结与使用建议 1、分析原因 我们都知道使用多线程的本质是为了提升程序的性能&#xff0c;总体来说有两个最核心的指标&#xff0c;一个延迟&#xff0c;一个吞吐量。延迟指的是发出请求到收到响应的时间&#xff0c;吞吐量指的是…

【golang】Reflect反射整理、值修改、反射结构体、应用

Reflect 整理 反射是用程序检查其所拥有的结构&#xff0c;尤其是类型的一种能力&#xff1b;这是元编程的一种形式。反射可以在运行时检查类型和变量&#xff0c;例如&#xff1a;它的大小、它的方法以及它能“动态地”调用这些方法。这对于没有源代码的包尤其有用。这是一个强…

C++引用概述

变量名实质上是一段连续存储空间的别名&#xff0c;是一个标号(门牌号)&#xff0c;程序中通过变量来申请并命 名内存空间&#xff0c;通过变量的名字可以使用存储空间。引用是 C中新增加的概念&#xff0c;引用可以看作 一个已定义变量的别名。 引用的语法&#xff1a; Type&…

第二章 探究活动Activity

一、Activity的用法 1. Activity 任何活动都应该重写Activity的onCreate()方法 项目中在res添加任何资源都会在R文件生成一个相应的资源id 所有的活动都要在AndroidManifest.xml中进行注册才能生效 <activityandroid:name".FirstActivity"android:label"T…

性能测试 —— Jmeter日志查看与分析

一、Jmeter日志概览 Jmeter日志文件保存在bin目录中&#xff0c;名称为jmeter.log。我们可以在面板中直接察看日志&#xff0c;点击右上角黄色标志物可以打开日志面板&#xff0c;再次点击收起 另外&#xff0c;Jmeter可以很方便地设置日志输出级别&#xff1a; 通过这种方式修…

MySQL-----事务

事务的概念 事务是一种机制&#xff0c;一个操作序列。包含了一组数据库的操作命令&#xff0c;所有的命令都是一个整体&#xff0c;向系统提交或者撤销的操作&#xff0c;要么都执行&#xff0c;要么都不执行。 是一个不可分割的单位 事务的ACID特点 ACID&#xff0c;是指在可…

【Spring】配置文件-properties和xml

文章目录 1. 前言2. properties配置文件3. xml配置文件4. 总结 1. 前言 在Spring中,配置文件有两种,properties配置文件和xml配置文件 properties配置文件&#xff0c;在Java编程中是一种常见的配置文件形式&#xff0c;文件后缀为“.properties”&#xff0c;属于文本文件。它…

LeetCode算法题解|​ 669. 修剪二叉搜索树​、108. 将有序数组转换为二叉搜索树、​538. 把二叉搜索树转换为累加树​

一、LeetCode 669. 修剪二叉搜索树​ 题目链接&#xff1a;669. 修剪二叉搜索树 题目描述&#xff1a; 给你二叉搜索树的根节点 root &#xff0c;同时给定最小边界low 和最大边界 high。通过修剪二叉搜索树&#xff0c;使得所有节点的值在[low, high]中。修剪树 不应该 改变…

数据库系统原理第一章:数据库系统概述详解

数据库系统概述 概述基本概念数据数据库数据库管理系统数据库系统 管理发展『人工管理阶段』『文件系统阶段』『数据库系统阶段』 系统结构结构分类三级模式两层映像与数据独立性 主页传送门&#xff1a;&#x1f4c0; 传送 概述 数据库系统原理课程是一门理论与实践相结合的课…

Spring 与 Spring Boot

什么是 Spring 可以理解 Spring 是一个框架。这个框架最早来源于在差不多的 20 年前的 2002 年。 在那个时候 Java 世界的开发还是以 EJB 为主&#xff0c;因为在这之前的大部分应用都会使用服务器客户端的应用模式。 其实这个模式在现在还是在使用的&#xff0c;例如 IBM 系统…

第一章 Python基础知识

文章目录 python介绍优点应用领域web框架学习小技巧 python安装linux运行第一个程序Windows 基础数据类型算术运算符变量与赋值操作符变量赋值操作符转义符 获取用户输入与注释获取用户注释 案例&#xff1a;简单计算器实现在这里插入图片描述 总结 python介绍 python是一种面…

博文总结:交叉熵损失函数与标签平滑

文章目录 基本概念交叉熵损失函数Pytorch代码实现参考文献 李宏毅机器学习2023作业04Self-attention、李宏毅机器学习2023作业03CNN和李宏毅机器学习2023作业02Classification都是分类问题&#xff0c;都涉及到了交叉熵损失函数以及起正则作用的标签平滑技巧&#xff0c;本次博…

项目实战:给首页上库存名称添加超链接然后带fid跳转到edit页面

1、提取公共方法common.js function $(key){if(key){if(key.startsWith("#")){key key.substring(1)return document.getElementById(key)}else{let nodeList document.getElementsByName(key)return Array.from(nodeList)}} } 2、 给库存名称添加超链接 2.1、inde…

Qt Creator创建新项目警告问题

这里可以看见如果你是一些高版本会出现各种警告&#xff0c;但是可以编译通过&#xff0c;这是ClangCodeModel模块导致 解决办法 help -> About Plugins..->C ->ClangCodeModel 帮助 -> 关于插件 -> c ->ClangCodeModel取消勾选 然后重启Qt即可

【Java初阶练习题】-- 循环+递归练习题

循环练习题02 打印X图形计算1/1-1/21/3-1/41/5 …… 1/99 - 1/100 的值输出一个整数的每一位如&#xff1a;123的每一位是3&#xff0c;2&#xff0c;1模拟登录使用方法求最大值求斐波那契数列的第n项。(迭代实现)求和的重载求最大值方法的重载递归求N阶乘递归求 1 2 3 ...…

Redis的安装及基本使用

⭐⭐ Redis专栏&#xff1a;Redis专栏 ⭐⭐ 个人主页&#xff1a;个人主页 目录 一.Redis的简介 ⭐ 拓展&#xff1a;NO-SQL数据库与SQL数据库 二.Redis的安装 2.1linux版安装 下载Redis Desktop 2.2 Windows安装 三.redis的基本使用 3.1 String 字符串类…