简单介绍
二分查找法(Binary Search)是一种在有序数组中查找目标值的高效算法。它的基本思想是通过将目标值与数组中间元素进行比较,从而缩小查找范围,直到找到目标值或确定它不存在为止。
二分查找的时间复杂度为O(log n)。
这是因为在每一次比较中,算法将搜索范围减半,因此搜索范围每次都会缩小一半。这种对搜索范围的对数级别的减少导致了O(log n)的时间复杂度。即使在最坏情况下,即未找到目标值时,二分查找也只需要进行O(log n)次比较。因此,二分查找在大型有序数组中仍然能够以较快的速度找到目标值或确定其不存在。
基础版
基本搜索算法
输入输出描述
要求在有序数组A里,查找数值target
如果找到就返回索引 找不到返回-1
算法逻辑
首先确定两个指针 i j
设置指针和初值
i指向0 索引 j指向n-1索引
以规定范围
再执行中间值和目标值比较的逻辑
用循环实现 while(i<=j)
取到中间索引 再java里两个int(整数)相除自动取整
再判断
目标值小于中间值 j向左移动
目标值大于中间值 i向右移动
目标值等于中间值 返回索引 即为中间索引
代码实现
import java.util.Scanner; public class Main { //简易版的二分查找法 public static int[] arr =new int[]{1,2,3,4,5,6,7,8,9}; public static void main(String[] args) { Scanner Dduo=new Scanner(System.in); System.out.println("请输入要查找的目标值"); int target=Dduo.nextInt(); if(Binarysearch(arr,arr.length,target)==-1) System.out.println("数组中不存在目标值"); else System.out.println("目标值"+target+"的索引为"+Binarysearch(arr,arr.length,target)); } public static int Binarysearch(int arr[],int n,int target){ //初始化查找指针 int i=0,j=n-1; //通过循环不断执行中间值和目标值比较的逻辑 while(i<=j){ //取到中间索引 int m=(i+j)>>>1; //目标再左边 if(target<arr[m]) j=m-1; //目标再右边 else if(arr[m]<target) i=m+1; //找到了 else return m; } return -1; } }
注意点
要注意目标值和中间索引对应的值比较时,是比较的大于小于,千千万万要考虑等于号
分三种情况
目标值大于中间索引所对应的数值 更新i的数值
目标值小于中间索引所对应的数值 更新j的数值
返回中间索引
i<=j 意味着区间内有未比较的元素
先比较后查找
是同步的 不可比较了不查找 一定要比较查找一次 是同时发生的
如果改成了i<j则不会进行查找 成功漏掉中间值未查找
(i+j)/2存在问题
可能会存在数值溢出的风险
java中将最高位当做了符号位
得到了负数
这就是两个正数先加得到负数的原因
一个16位的二进制数 将最高位视为符号位和不视为符号位 代表的数字不同
所以要使用无符号右移运算符>>>
因为数组为升序排列
所以
指针的比较写成小于符号
目标值和中间索引m所对应的数值比较时 都用小于符号 会更加美观 不变扭
无符号右移运算符
" >>> "
十进制 16
对应二进制 0000_1000
将二进制所有0和1向右边移动
二进制 0000_0100
对应十进制 8
即实现了除2
奇数 同理 实际效果为 取整
7>>>1 为3
改动版
平衡版
如果元素在最左边要执行L次
那么元素在最右边要执行2L次
左边找元素成本低 因为只要比较一次就行
else if是造成不平衡的原因
左闭右开的区间,i指向的可能是目标,而j指向的不是目标
不在循环内找出,等范围内只剩i时,退出循环,在循环外比较a[i]和target
循环内的平均比较次数减少了
时间复杂度O-(log(n))
因为渐近上界和渐近下界一样
所以我们用渐进紧界表示
也算是一个缺点,可以忽略,从严格意义上不算是缺点
import java.util.Scanner; public class Main { public static void main(String[] args) { //创建Scanner类的对象 Scanner sc=new Scanner(System.in); //定义数组的长度 int n= sc.nextInt(); //输入数组的数值 int arr[]=new int[n]; for (int i = 0; i < n; i++) arr[i]= sc.nextInt(); //输入待查找数值 int taget= sc.nextInt(); //调用二分查找法 binarySearch(arr,taget); } //访问修饰符public表示公有化方法 是权限最大的访问修饰符权限修饰符 //即可以可以在同一个类,同一个类的其他方法,不同包下的子类,不同包下的其他类中使用 //被static修饰的方法独立于该类的任何对象 //也就是说,这些变量和方法不属于任何一个实例对象,而是被类的实例对象所共享; //其实意思就是都可以用 public static int binarySearch(int a[], int target){ //指定两个指针 int i=0,j=a.length; while(1<j-i){ int m=(i+j)>>>1; if(target<a[m]) //右指针左移 j=m; else //左指针右移 i=m; } if(a[i]==target) //找到了 return i; //没找到 else return -1; }; }
自己总结的公式
实际开发中的应用
我们会将执行判断的核心逻辑放入方法中
check方法就是判断使用的
注意要将算法中的所有变量都放入静态区