二分查找

二分查找

思想就是我们传统的猜数思想,别人心里想一个数,给你范围,让你进行最少次数的猜测,你肯定先从中间开始猜测,不断折半猜,直到猜到正确的为止。也就是针对一个有序集合,不断缩小区间,直到找到要找的数为止。时间复杂度logn,推理一下:寻找大小为n的数组一个数所需要的区间缩小变化1/2*k=n ,k次缩小,logn=k

适用场景
(1)适用于顺序表结构,用链表实现也可,但是要多加一个数据域,就是index域,但是时间复杂度特别高,因为每次都要遍历到那个中间结点才行。

(2)数据是有序的

(3)数据量不能过小,不能过大。过小则和顺序查找效率差不多,但如果数据较大,数据比较比较费事,则用二分查找比顺序查找要好。过大由于顺序表的缘故,对连续内存要求,可能会溢出。

package search;
//二分查找
public class BinarySearch {

	public static void main(String[] args) {
		int[] a= {1,4,5,7,8,9};
		System.out.println(binarySearch(a,7));

	}
	public static int binarySearch(int[] a,int x) {
		int low=0,high=a.length-1,middle=-1;
		while(low<=high) {
			middle=low+((high-low)>>1);
			if(a[middle]==x) {
				return middle;
			}
			else if(a[middle]<x) {
				low=middle+1;
			}
			else
				high=middle-1;
		}
		return -1;
	}
}

注意:
循环退出条件low<=high;
middle=low+((high-low)>>1),如果用middle=(low+high)/2数据大可能会溢出。移位运算部分要用括号,因为移位运算优先级低于加减法优先级;
low,high不能直接是middle,不然可能死循环

其他变种

package search;
//二分查找的变种 针对有重复数字的数组等
public class StrangeBinarySerach {

   public static void main(String[] args) {
   	int[] a= {1,4,5,7,7,8,9};
   	System.out.println(firstIndex(a,7));
   	System.out.println(lastIndex(a,7));
   	System.out.println(maxEqualIndex(a,7));
   	System.out.println(minEqualIndex(a,7));

   }
   //查找第一个等于给定值的数
   public static int firstIndex(int[] a,int value) {
   	int low=0,high=a.length;
   	while(low<=high) {
   		int mid=low+((high-low)>>1);
   		if(a[mid]<value) {
   			low=mid+1;
   		}
   		else if(a[mid]>value) {
   			high=mid-1;
   		}
   		else {
   			if(mid==0||a[mid-1]!=value)//如果是第一个数,或者当前数前面的数不等于value,证明当前就是要查找的数
   				return mid;
   			else
   				high=mid-1;//否则要找的数一定在low到middle之间
   		}
   	}
   	return -1;
   }
   //查找最后一个等于给定值的数
   public static int lastIndex(int[] a,int value) {
   	int low=0,high=a.length;
   	while(low<=high) {
   		int mid=low+((high-low)>>1);
   		if(a[mid]<value) {
   			low=mid+1;
   		}
   		else if(a[mid]>value) {
   			high=mid-1;
   		}
   		else {
   			if(mid==0||a[mid+1]!=value)//如果是第一个数,或者当前数后面的数不等于value,证明当前就是要查找的数
   				return mid;
   			else
   				low=mid+1;//否则要找的数一定在middle到high之间
   		}
   	}
   	return -1;
   }
   //查找第一个大于等于给定值的数
   public static int maxEqualIndex(int[] a,int value) {
   	int low=0,high=a.length;
   	while(low<=high) {
   		int mid=low+((high-low)>>1);
   		if(a[mid]>=value) {
   			if(mid==0||a[mid-1]<value)//如果是第一个数,或者当前数前面的数小于value,证明当前就是要查找的数
   				return mid;
   			else
   				high=mid-1;//否则要找的数一定在middle到high之间
   		}
   		else {
   			low=mid+1;
   		}
   	}
   	return -1;		
   }
   //查找最后一个小于等于给定值的数
   public static int minEqualIndex(int[] a,int value) {
   	int low=0,high=a.length;
   	while(low<=high) {
   		int mid=low+((high-low)>>1);
   		if(a[mid]<=value) {
   			if(mid==0||a[mid+1]>value)//如果是第一个数,或者当前数后面的数大于value,证明当前就是要查找的数
   				return mid;
   			else
   				low=mid+1;//否则要找的数一定在low和middle之间
   		}
   		else {
   			high=mid-1;
   		}
   	}
   	return -1;	
   }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值