通过Java实现快速查找某个元素在有序集合中的位置(二分查找法,又名折半查找法)

本文介绍了如何使用Java实现二分查找法,一种在有序集合中快速定位元素的算法。通过连续的折半操作,大大减少了查找次数。文章详细解释了算法逻辑,并提供了具体的代码示例。

前言:

1、二分查找法又叫折半查找法,从名字来看,能大概明白它的算法逻辑
2、二分查找法必须满足被搜索的集合必须是有序的
3、待查找的元素是在集合中真实存在的

算法:

1、二分查找法每次搜索都是按照搜索区域中间位置的元素进行定位,首次搜索时,开始位置为0,结束位置为集合长度-1,中间位置=(开始位置+结束位置)/2
2、如果中间位置的元素正好与待查找的元素相同,则直接返回结果
3、如果中间位置的元素值大于待查找的元素值,则表示待查找元素在集合的左半区域,那么搜索范围将会缩小到原来的一半,右半边的区域将会被舍弃掉,搜索的结束位置=中间位置-1,开始位置不变
4、如果中间位置的元素值小于带查找的元素值,则表示待查找元素在集合的右半区域,那么搜索范围将会缩小到原来的一半,左半区域将会被舍弃掉,搜索的开始位置=中间位置+1,结束位置不变

例如:

1、有序数组arr={1,3,4,5,7,9,10,15,18,30,50,100}
2、有序数组arr总长度:12
3、数组首个元素位置:0
4、数组中间元素位置:5
5、数组末尾元素位置:11

第一次查找:

开始位置:0
结束位置:11
中间位置:5
中间位置的值:9
比较中间位置的值和待查找元素:9 > 5,则舍掉9以后的数据,继续搜索9之前的数据
下一次搜索范围:{1,3,4,5,7}

第二次查找:

开始位置:0
结束位置:第一次的中间位置-1 = 5-1 = 4
中间位置:(开始位置 + 结束位置)/2 = (0 + 4) / 2 = 2
中间位置的值:4
比较中间位置的值和待查找元素:4 < 5,则舍弃掉4之前的数据,继续搜索4之后的数据
下一次搜索范围:{5,7}

第三次查找:

开始位置:第二次的中间位置 + 1 = 2 + 1 = 3
结束位置:4
中间位置:(开始位置+结束位置)/2
中间位置的值:5
比较中间位置的值和待查找元素:5 = 5,则结束查询

注意:

1、每次搜索之后的集合是没有变的,只是搜索范围在随着开始位置和结束位置的变化而缩小
2、最高效的时候就是搜索一次的时候正好在中间的位置,这个时候只会搜索一次
3、最低效的时候就是将搜索范围缩小到1的时候
4、分解原理:
第1次搜索时为n/2⁰,搜索第2次为n/2¹,搜索第3次为n/2²,搜索第4次为n/2³...以此类推,到第k次的时候即为n/2^(k-1),当分解到最后时候,只会剩下1个元素,所以n/2^(k-1)>=1,极限的情况下,n/2^(k-1)=1,则n=log2(k-1),所以二分法的时间复杂度为O(logn)

二分查找法代码:

	/**
	 * 1,数组必须是顺序结构的数组,如果不是顺序结构的,需要先进行排序
	 * 2,如果数组中存在相同数字的,只会返回其中一个的位置,不会返回两个的位置
	 * 3,二分查找法是在缩短数组的查找范围,所以开始位置的结束位置是在随时变化的
	 * 4,开始位置变化的情况:当中间位置的值小于待查找数字的时候,开始位置 = 中间位置 + 1(表示待查找数字在数组的右半边区域中)
	 * 5,结束位置变化的情况:当中间位置的值大于待查找数字的时候,结束位置 = 中间位置 - 1(表示待查找数字在数组的左半边区域中)
	 * @param arr
	 * @param target
	 * @return
	 */
	public static int halve(int[]arr, int target) {
		// 开始位置
		int s_pos = 0;
		// 结束位置(即数组长度)
		int e_pos = arr.length - 1;
		while(s_pos <= e_pos) {
			// 中间位置 = (开始位置 + 结束位置 ) / 2
			int m_pos = ( s_pos + e_pos ) >>> 1; // 无符号右移1位,即/2
			// 如果被查询的数字大于中间位置的值,则表示该数在数组的前半区域,则将结束位置设置为中间位置-1
			if(target < arr[m_pos]) {
				e_pos = m_pos - 1;
			}
			// 如果被查询的数字大于中间位置的值,则表示该数在数组的后半区域,则将开始位置设置为中间位置+1
			else if(target > arr[m_pos]) {
				s_pos = m_pos + 1;
			}
			// 如果找到了数字则直接返回
			else {
				return m_pos;
			}
		}
		return -1; //表示没有找到查找的数字:1,可能数字根本不在数组中;2,数组不是顺序结构的
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值