数据结构 -- 二分查找

本文主要梳理了二分查找算法的几种实现思路,基本概念参考 顺序、二分、哈希查找的区别及联系_生成一个大小为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]与target3.循环内的平均比较次数减少了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;elsereturn 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.mzph.cn/news/819760.shtml

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

相关文章

java--包装类

目录 1、包装类的定义 2、意义 3、八大基本类型的包装类 4、转换 5、自动拆箱和自动装箱 6、面试问题&#xff1a;请阐述128陷阱以及出现的原因 1、包装类的定义 把基本类型包装--包装类 2、意义 1、在面向对象中&#xff0c;“一切皆为对象”&#xff0c;但是基本类型不…

手机移动端网卡信息获取原理分析

有些场景我们需要获取当前手机上的网卡信息&#xff08;如双卡双待、Wifi等&#xff09;。本文准备研究一下这块的原理&#xff0c;以便更好的掌握相关技术原理。 1、底层系统接口 getifaddrs 使用 getifaddrs 接口可以达到我们的目的&#xff0c;该接口会返回本地所有网卡的信…

fiddler使用(三)-工具栏介绍

Fiddler是一个强大的网络调试工具&#xff0c;它可以帮助用户捕获HTTP和HTTPS请求和响应&#xff0c;从而进行调试和分析。在Fiddler的用户界面中&#xff0c;工具栏是一个非常重要的组成部分&#xff0c;它提供了许多常用的操作和功能&#xff0c;方便用户进行网络调试。以下是…

3d max快捷键命令大全

文章目录 3dmax快捷键汇总一、主界面快捷键1、菜单快捷键2、主工具栏和浮动工具栏快捷键3、视口快捷键4、关键点和时间控制项快捷键5、视口导航控制项快捷键6、方形菜单快捷键7、虚拟视口快捷键8、次对象快捷键9、层次快捷键10、可编辑网格快捷键11、可编辑多边形快捷键12、NUR…

分组带给了我们哪些?

在我们的班级里&#xff0c;你们可能已经注意到我们最近进行了一项特别的举措——分组学习。你们可能会想&#xff0c;为什么我们要这样做&#xff1f;今天&#xff0c;我想与大家分享一些关于分组学习的见解和想法。请读下面的两个故事。 --- 故事一&#xff1a;亚马逊团队创…

布局香港之零售中小企篇 | 传承之味,迈向数字化经营的时代

随着内地与香港两地经贸合作日渐紧密&#xff0c;越来越多内地消费品牌将目光投向香港这片充满机遇的热土&#xff0c;纷纷入驻香港市场。「北店南下」蔚然成风&#xff0c;其中不乏已在内地市场深耕多年的传统老字号。数字化经营时代&#xff0c;老字号焕新刻不容缓&#xff0…

蓝队面试经验总结

Sql注入 1、sql注入漏洞原理 开发者没有在网页传参点做好过滤&#xff0c;导致恶意 sql 语句拼接到数据库进行执行 2、sql注入分类 联合注入 、布尔盲注 、时间盲注 、堆叠注入 、宽字节注入 、报错注入 3、堆叠注入原理 在 mysql 中&#xff0c;分号 代表一个查询语句的…

Git-常规用法-含解决分支版本冲突解决方法

目录 前置条件 已经创建了Gitee账号 创建一个远程仓库 Git的优点 版本控制 Git 下载 Git的使用 检查Git的是否安装成功 git的常用命令 常用流程 Git 分支 分支流程 Git 远程仓库 远程仓库流程 特殊 可能遇到的问题 前置条件 已经创建了Gitee账号 创建一个远程仓…

求1000以内正整数的平方根(C语言)

一、运行结果&#xff1b; 二、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h> # include <math.h>int main() {//初始化变量值&#xff1b;int number 0;int result 0;//提示用户&#xff1b;printf("请输入1000以内求平方根的…

【c++leetcode】14. Longest Common Prefix

问题入口 解决方案 class Solution { public:string longestCommonPrefix(vector<string>& v) {string ans "";sort(v.begin(), v.end());int n v.size();string first v[0],last v[n - 1];for(int i 0; i < min(first.size(),last.size()); i){…

密码学 | 椭圆曲线数字签名方法 ECDSA(下)

目录 10 ECDSA 算法 11 创建签名 12 验证签名 13 ECDSA 的安全性 14 随机 k 值的重要性 15 结语 ⚠️ 原文&#xff1a;Understanding How ECDSA Protects Your Data. ⚠️ 写在前面&#xff1a;本文属于搬运博客&#xff0c;自己留着学习。同时&#xff0c;经过几…

树莓派安装Nginx服务结合内网穿透实现无公网IP远程访问

文章目录 1. Nginx安装2. 安装cpolar3.配置域名访问Nginx4. 固定域名访问5. 配置静态站点 安装 Nginx&#xff08;发音为“engine-x”&#xff09;可以将您的树莓派变成一个强大的 Web 服务器&#xff0c;可以用于托管网站或 Web 应用程序。相比其他 Web 服务器&#xff0c;Ngi…

centos8 安装 jenkins

配置centos8 yum源 cd /etc/yum.repos.d mkdir bak mv *.repo bak wget https://mirrors.aliyun.com/repo/Centos-8.repo 安装java11 dnf install java-11-openjdk-devel 启用 Jenkins 源仓库 sudo wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat-s…

CentOS7.9上安装Oracle11g详解

目录 一、环境准备1.安装依赖2.查看libaiobaio版本3.修改host&#xff0c;绑定主机名4.关闭selinux 二、安装配置1.创建组、用户2.修改内核参数3.配置Oracle用户参数4.修改/etc/pam.d/login 文件5.修改/etc/profile 文件6.创建数据库相关目录7.安装包上传、解压8.添加环境变量 …

修改element-ui中el-calendar(日历)的样式

效果图如下&#xff1a; <template><div class"dashboard-container"><el-card style"width: 350px; height: auto; border-radius: 8px"><div class"custom-style"><p class"new-data">{{ newDate }}&…

macbook怎么录屏幕视频?两款实用工具推荐!

在数字化时代&#xff0c;录制屏幕视频已成为我们日常生活和工作中不可或缺的一部分。MacBook作为一款广受欢迎的电脑品牌&#xff0c;为我们提供了高效且便捷的屏幕录制方式&#xff0c;可是很多用户不知道macbook怎么录屏幕视频。本文将介绍两种在Mac上录制屏幕视频的方法&am…

OpenCV——SUSAN边缘检测

目录 一、SUSAN算法二、代码实现三、结果展示 OpenCV——SUSAN边缘检测由CSDN点云侠原创&#xff0c;爬虫自重。如果你不是在点云侠的博客中看到该文章&#xff0c;那么此处便是不要脸的爬虫。 一、SUSAN算法 Susan边缘检测是一种经典的边缘检测算&#xff0c;它由Susan Smith…

【muduo源码学习】one-loop-per-thread核心原理

在 TCP 网络编程中&#xff0c;这里我们特指在单机的环境下&#xff0c;主要关注两件事。第一&#xff0c;如何正确的处理TCP的连接和断开&#xff0c;以及正确处理数据的收发&#xff1b;在错综复杂的网络环境中&#xff0c;这并非易事&#xff0c;涉及很多细节。第二&#xf…

【JAVA基础篇教学】第十七篇:Java单元测试

博主打算从0-1讲解下java基础教学&#xff0c;今天教学第十七篇&#xff1a;Java单元测试。 单元测试和集成测试是软件开发过程中至关重要的一部分&#xff0c;它们可以帮助确保代码的质量和稳定性。下面我将为您提供详细说明和代码案例。 一、单元测试&#xff08;Unit Test…

27、Lua 学习笔记之五(Lua中的数学库)

Lua中的数学库 Lua5.1中数学库的所有函数如下表&#xff1a; math.pi 为圆周率常量 3.14159265358979323846 数学库说明例子方法abs取绝对值math.abs(-15)15acos反余弦函数math.acos(0.5)1.04719755asin反正弦函数math.asin(0.5)0.52359877atan2x / y的反正切值math.atan2(9…