数据结构 -- 二分查找

news2024/9/20 9:28:47

本文主要梳理了二分查找算法的几种实现思路,基本概念参考 顺序、二分、哈希查找的区别及联系_生成一个大小为10万的有序数组,随机查找一个元素,分别采用顺序查找和二分查找方式-CSDN博客

1、基本概念

(1)前提条件:待查找数据必须有序。

(2)实现方式:在查找过程中,它先和中间的比较,如果等于就直接返回,如果小于就在前半部分继续使用二分法进行查找,如果大于则在后半部分继续使用二分法进行查找。

2、算法实现

2.1 基本版实现

package com.hh.algorithm.find;

public class BinarySearch {

    public static void main(String[] args) {
        int[] arr = {1,2,4,5,5,6,7,8,9,11,23};
        System.out.println(BinarySearch.binary(arr, 4));
    }
    public static int binary(int[] arr, int key) {
        int i = 0;
        int j = arr.length - 1;
        while (i <= j) {
            int mid = (i + j) >>> 1;
            if (key < arr[mid]) {
                j = mid - 1;
            } else if (key > arr[mid]) {
                i = mid + 1;
            } else {
                return mid;
            }
        }
        return -1;
    }

}

问题1:为什么是 i<=j ,而不是 i<j?

(1)i==j:意味着 i,j 它们指向的元素也会参与比较;

(2)i<j:只意味着mid 指向的元素参与比较。

问题2:j - ((j - i) >> 1) 与 (i+j)/2都是相加除2,使用后者有没有问题?

当超出 int 的范围时,他会把最高位视为符号位。

代码实现

package com.hh.algorithm.find;

public class BinarySearchTest {

    public static void main(String[] args) {
         /*
        同一个二进制数
        1011 1111 1111 1111 1111 1111 1111 1110

        没有超出int 范围,默认是:不把最高位视为符号位,代表3221225470
        超出int 范围,把最高位视为符号位,代表-1073741826

        所以,当计算结果超出int的范围时,他就会把最高位视为符号位
         */
        int i = 0;
        int j = Integer.MAX_VALUE - 1;

        int mid = (j + i) / 2;
        int mid2 = (i + j) >>> 1;
        System.out.println("第1轮(j + i) / 2:" + mid);
        System.out.println("第1轮(j+i)/2:" + mid2);

        System.out.println("---------------------");
        i = mid+1;
        mid = (j + i) / 2;
        mid2 = (i + j) >>> 1;
        System.out.println("第2轮(j + i) / 2:" + mid);
        System.out.println("第2轮(j+i)/2:" + mid2);
        /*
           扩展:
           (1)(j + i) / 2还有另一种写法,也就是 j - (j - i) / 2
           (2)j - (j - i) / 2 拆开就是 j - j/2 + i/2  --> j/2 + i/2  --> (j + i) / 2
         */
    }
}

运行结果

2.2 平衡版实现

package com.hh.algorithm.find;
/*
            // 如果待查找数字一直在左边,if那么就会判断比较log(n)次
            if (key < arr[mid]) {
                j = mid - 1;
            } else if (key > arr[mid]) {
                // 如果待查找数字一直在右边,if那么就会判断比较2log(n)次
                i = mid + 1;
            } else {
                return mid;
            }
         解决方式:
            1.左闭右开的区间,i指向的可能是目标,而j指向的不是目标
            2.不在循环内找出,等范围内只剩i时,退出循环,在循环外比较 a[i]与target
            3.循环内的平均比较次数减少了
            4.时间复杂度    θ(log(n))
*/
public class BinarySearch2 {

    public static void main(String[] args) {
        int[] arr = {1,2,4,5,5,6,7,8,9,11,23};
        System.out.println(BinarySearch2.binary(arr, 4));
    }

    public static int binary(int[] arr, int key) {
        int i = 0;
        int j = arr.length;
        while (i + 1 < j) {
            int mid = (i + j) >>> 1;
            if (key < arr[mid]) {
                j = mid;
            } else{
                i = mid;
            }
        }
        return (key == arr[i])? i : -1;
    }

}

运行结果

2.3 java版实现

package com.hh.algorithm.find;

/**
 * 下面是java版本的二分查找代码实现,粘贴了底层代码
 */
public class BinarySearch3 {

    public static void main(String[] args) {
        int[] arr = {1,2,4,5,5,6,7,8,9,11,23};
        System.out.println(BinarySearch3.binarySearch(arr,4));
    }
    public static int binarySearch(int[] a, int key) {
        return binarySearch0(a, 0, a.length, key);
    }
    private static int binarySearch0(int[] a, int fromIndex, int toIndex,
                                     int key) {
        int low = fromIndex;
        int high = toIndex - 1;

        while (low <= high) {
            int mid = (low + high) >>> 1;
            int midVal = a[mid];

            if (midVal < key)
                low = mid + 1;
            else if (midVal > key)
                high = mid - 1;
            else
                return mid; // key found
        }
        //没找到就返回插入点位置
        return -(low + 1);  // key not found.
    }
}

运行结果

2.4 有重复元素的数组,返回左右

package com.hh.algorithm.find;

/**
 * 当该数组有重复元素时,返回最靠左(右)的元素位置
 */
public class BinarySearchMost {

    public static void main(String[] args) {
        int[] arr = {1,2,4,5,7,7,7,7,11,23};
        System.out.println(BinarySearchMost.binaryLeft(arr,7));
        System.out.println(BinarySearchMost.binaryRight(arr,7));
    }
    /*
        返回最靠左的元素索引
     */
    public static int binaryLeft(int[] arr, int key) {
        int i = 0;
        int j = arr.length - 1;
        int candidate = -1;
        while (i <= j) {
            int mid = (i + j) >>> 1;
            if (key < arr[mid]) {
                j = mid - 1;
            } else if (key > arr[mid]) {
                i = mid + 1;
            } else {
                candidate = mid;
                j = mid -1;
            }
        }
        return candidate;
    }
    /*
    返回最靠右的元素索引
 */
    public static int binaryRight(int[] arr, int key) {
        int i = 0;
        int j = arr.length - 1;
        int candidate = -1;
        while (i <= j) {
            int mid = (i + j) >>> 1;
            if (key < arr[mid]) {
                j = mid - 1;
            } else if (key > arr[mid]) {
                i = mid + 1;
            } else {
                candidate = mid;
                i = mid +1;
            }
        }
        return candidate;
    }
}

运行结果

2.5 没找到返回有意义的值

package com.hh.algorithm.find;

/**
 * 当该数组找不到该元素时,返回大于(小于)等于目标的最靠左(右)的索引位置
 */
public class BinarySearchMost2 {

    public static void main(String[] args) {
        int[] arr = {1,2,4,5,7,7,7,7,11,23};
        System.out.println(BinarySearchMost2.binaryLeft(arr,3));
        System.out.println(BinarySearchMost2.binaryRight(arr,9));
    }
    /*
        返回大于目标的最靠左索引
     */
    public static int binaryLeft(int[] arr, int key) {
        int i = 0;
        int j = arr.length - 1;
        while (i <= j) {
            int mid = (i + j) >>> 1;
            if (key <= arr[mid]) {
                j = mid - 1;
            } else{
                i = mid + 1;
            }
        }
        return i;
    }
    /*
    返回最小于目标的最靠右索引
 */
    public static int binaryRight(int[] arr, int key) {
        int i = 0;
        int j = arr.length - 1;
        while (i <= j) {
            int mid = (i + j) >>> 1;
            if (key < arr[mid]) {
                j = mid - 1;
            } else {
                i = mid +1;
            }
        }
        return i-1;
    }
}

运行结果

本文为学习笔记,所参考文章均已附上链接,若有疑问请私信!

创作不易,如果对你有点帮助的话麻烦点个赞支持一下!

新手小白,欢迎留言指正!

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

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

相关文章

Leetcode二叉树刷题

给你一个二叉树的根节点 root &#xff0c; 检查它是否轴对称。 示例 1&#xff1a; 输入&#xff1a;root [1,2,2,3,4,4,3] 输出&#xff1a;true public boolean isSymmetric(TreeNode root) {if(rootnull)return true;return compare(root.left,root.right);}public boole…

【Unity】游戏场景添加后处理特效PostProcessing

添加后处理特效PostProcessing 添加雾效果后处理何为后处理&#xff1f;添加后处理特效 添加雾效果 依次点击Window -> Rendering -> Lighting添加Lighting面板。 点击Lighting里面的Environment&#xff0c;找到Other Setting 将Fog选项勾选 更改下方的颜色 调整雾的浓…

自然语言处理: 第二十七章LLM训练超参数

前言: LLM微调的超参大致有如下内容,在本文中&#xff0c;我们针对这些参数进行解释 training_arguments TrainingArguments(output_dir"./results",per_device_train_batch_size4,per_device_eval_batch_size4,gradient_accumulation_steps2,optim"adamw_8bi…

JavaSE图书管理系统

JavaSE图书管理系统 思路一.Main方法二.User包1.User类2.NormaUser类3.AdminUser类三.book包1.BookList类2.Book类四.operation包1.IOPeration接口2.AddOperation类新增图书3.BorrowOperation类借阅图书4.DelOperation类删除图书5.FindOperation类查找图书6.ReturnOperation类归…

Unity解决:导出安卓apk 安装时报错:应用未安装:软件包似乎无效

Unity2018.4.36 导出安卓apk 安装时报错&#xff1a;应用未安装&#xff1a;软件包似乎无效 解决办法&#xff1a;因为安装到安卓12 需要添加添加过滤规则 在AS工程AndroidManifest.xml 添加过滤规则即可。 android:exported"true"

初识ansible服务剧本playbook及剧本编写实例

目录 1、playbook剧本文件概念 1.1 剧本文件的结构由4部分组成 2、配置实例 实例1-编写一个实现批量安装mariadb数据库的剧本 实例2-编写一个创建一个目录/backup,并在目录喜爱创建01.txt文件的剧本 实例3-编写一个添加定时同步时间的定时任务剧本 错误反思 1、playbook剧…

MDK-ARM Keil5.38 下载安装环境搭建

一、keil软件介绍 KEIL是公司的名称&#xff0c;有时候也指KEIL公司的所有软件开发工具&#xff0c;目前2005年Keil由ARM公司收购&#xff0c;成为ARM的公司之一。 MDK&#xff08;Microcontroller Development Kit&#xff09; 也称MDK-ARM、KEIL MDK、RealView MDK、KEIL For…

不需要GPU就可以玩转模型,同时支持本地化部署

简单一款不需要GPU就可以在Win 机器跑的模型&#xff1a;Ollama&#xff1b;用于本地运行和部署大型语言模型&#xff08;LLMs&#xff09;的开源工具 关于Ollama的简要介绍 平台兼容性&#xff1a;Ollama支持多种操作系统&#xff0c;包括macOS、Linux和Windows&#xff0c;…

linux系统USB/IP远程共享USB设备 —— 筑梦之路

概述 USB/IP 是一个开源项目&#xff0c;已合入 Kernel&#xff0c;在 Linux 环境下可以通过使用 USB/IP 远程共享 USB 设备。 USB Client&#xff1a;使用USB的终端&#xff0c;将server共享的usb设备挂载到本地。 USB Server&#xff1a;分享本地的usb设备至远程。 架构原理…

蓝桥杯2024年第十五届省赛真题-R 格式(高精度乘法 + 加法)

本题链接&#xff1a;蓝桥杯2024年第十五届省赛真题-R 格式 - C语言网 题目&#xff1a;​​​​​​​ 样例&#xff1a; 输入 2 3.14 输出 13 思路&#xff1a; 根据题意&#xff0c;结合数据范围&#xff0c;这是一道模板的高精度乘以低精度问题。 题意是double 类型 d 与…

vue3从精通到入门4:diff算法的实现

Vue 3 的 diff 算法相较于 Vue 2 有了一些改进和优化&#xff0c;主要是为了应对更复杂的组件结构和更高的性能需求。 以下是 Vue 3 diff 算法在处理列表更新时的大致步骤&#xff1a; 头头比较&#xff1a;首先&#xff0c;比较新旧列表的头节点&#xff08;即第一个节点&…

参会记录|全国多媒体取证暨第三届多媒体智能安全学术研讨会(MAS‘2024)

前言&#xff1a;2024年4月13日上午&#xff0c;我与实验室的诸位伙伴共聚江西南昌的玉泉岛大酒店&#xff0c;参加了为期一天半的全国多媒体取证暨第三届多媒体智能安全学术研讨会&#xff08;MAS’2024&#xff09;。本届学术研讨会由江西省计算机学会、江西省数字经济学会主…

如何高效部署和扩展AI模型:开源平台与无服务器架构的综合应用

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

java的深入探究JVM之类加载与双亲委派机制

前言 前面学习了虚拟机的内存结构、对象的分配和创建&#xff0c;但对象所对应的类是怎么加载到虚拟机中来的呢&#xff1f;加载过程中需要做些什么&#xff1f;什么是双亲委派机制以及为什么要打破双亲委派机制&#xff1f; 类的生命周期 类的生命周期包含了如上的7个阶段&a…

【Linux C | 多线程编程】线程同步 | 总结条件变量几个问题

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; ⏰发布时间⏰&#xff1a; 本文未经允许…

visual studio连接ubuntu不成功原因(SSH问题)及解决办法

原因1&#xff1a; 网络没有互通&#xff08;一般VMware&#xff09; 使用ping来看网络是不是可以互通&#xff0c;例如&#xff1a; //这里的ip是ubuntu的ip&#xff0c;也可以从ubuntu的客户端ping一下当前主机 ping 192.168.1.101原因2&#xff1a; SSH没有密钥&#xf…

如何构建云原生安全?云安全的最佳实践

理解云原生安全 在数字时代&#xff0c;云计算已经成为企业的标配&#xff0c;大多数企业都已经将自己的应用程序和数据迁移到了云上。然而&#xff0c;随着企业规模不断扩大&#xff0c;云安全问题也逐渐浮出水面。云安全最新的趋势是云原生安全&#xff0c;这是指在云环境中构…

深入理解数据结构第六弹——排序(3)——归并排序

排序1&#xff1a;深入了解数据结构第四弹——排序&#xff08;1&#xff09;——插入排序和希尔排序-CSDN博客 排序2&#xff1a;深入理解数据结构第五弹——排序&#xff08;2&#xff09;——快速排序-CSDN博客 前言&#xff1a; 在前面&#xff0c;我们已经学习了插入排序…

基于Springboot+Vue的Java项目-在线视频教育平台系统(附演示视频+源码+LW)

大家好&#xff01;我是程序员一帆&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;Java毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计 &am…

解析OceanBase v4.2 Oracle 语法兼容之 LOCK TABLE

背景 在OceanBase V4.1及之前的版本中&#xff0c;尽管已经为Oracle租户兼容了LOCK TABLE相关的语法&#xff0c;包括单表锁定操作&#xff0c;和WAIT N&#xff0c; NOWAIT 关键字。但使用时还存在一些限制。例如&#xff1a;LOCK TABLE只能针对单表进行锁定&#xff0c;并不…