二分查找算法及其优化

本文介绍了二分查找算法的两种优化方式:插值查找和斐波那契查找。插值查找通过改变划分比例提高效率,斐波那契查找利用黄金分割比进行高效分割。这两种优化算法虽然时间复杂度仍为O(logn),但在特定情况下能提升查找效率。

二分查找是一种非常高效的算法,又称折半查找,下面用递归和非递归实现

二分查找的思想
有序序列,每次取序列的中间元素和目标元素进行对比,每次缩小一半的查找范围,这样直到找到为止。

二分查找图示说明:(图片来自百度)
在这里插入图片描述使用递归实现

public static int recursionBinarySearch(int[] arr,int key,int low,int high){
		
		if(key < arr[low] || key > arr[high] || low > high){
			return -1;				
		}
		
		int middle = (low + high) / 2;			//初始中间位置
		if(arr[middle] > key){
			//比关键字大则关键字在左区域
			return recursionBinarySearch(arr, key, low, middle - 1);
		}else if(arr[middle] < key){
			//比关键字小则关键字在右区域
			return recursionBinarySearch(arr, key, middle + 1, high);
		}else {
			return middle;
		}	
		
	}

使用非递归实现

public static int commonBinarySearch(int[] arr,int key){
		int low = 0;
		int high = arr.length - 1;
		int middle = 0;			//定义middle
		
		if(key < arr[low] || key > arr[high] || low > high){
			return -1;				
		}
		
		while(low <= high){
			middle = (low + high) / 2;
			if(arr[middle] > key){
				//比关键字大则关键字在左区域
				high = middle - 1;
			}else if(arr[middle] < key){
				//比关键字小则关键字在右区域
				low = middle + 1;
			}else{
				return middle;
			}
		}
		
		return -1;		//最后仍然没有找到,则返回-1
	}

时间复杂度
采用分治策略,最坏情况下时间复杂度为O(log2 N)
2^x=n;
最坏情况要折半x次才找到,则x=logn。
最好情况为O(1)

二分查找算法的两种优化

优化一:插值查找算法
可以发现二分查找每次都是选取中间的那个记录关键字作为划分依据的,那为什么不可以是其他位置的关键字呢?在有些情况下,使用二分查找算法并不是最合适的。举个例子:在1-1000中,一共有1000个关键字,如果要查找关键字10,按照二分查找算法,需要从500开始划分,这样的话效率就比较低了,所以有人提出了插值查找算法。说白了就是改变划分的比例,比如三分或者四分。

插值查找算法对二分查找算法的改进主要体现在mid的计算上,其计算公式如下:
在这里插入图片描述
而原来的二分查找公式是这样的:
在这里插入图片描述
所以我们发现主要变化的地方是1/2这个系数。其思想可以总结如下:
插值查找是根据要查找的关键字的key与查找表中最大最小记录的关键字比较之后的查找算法,其核心是上述计算mid的计算公式。由于大体框架与二分查找算法是一致的,所以时间复杂度仍然是O(logn)。

优化二:斐波那契查找算法
从前面的分析中可以看到,无论划分的关键字太大或者太小都不合适,所以又有人提出了斐波那契查找算法,其利用了黄金分割比原理来实现的。
一个数列如果满足F(n)=F(n-1)+F(n-2),则称这个数列为斐波那契数列。在斐波那契查找算法中计算mid的公式如下:
在这里插入图片描述
斐波那契查找的前提是待查找的查找表必须顺序存储并且有序。波那契查找与折半查找很相似,他是根据斐波那契序列的特点对有序表进行分割的

要求开始表中记录的个数为某个斐波那契数小1,及n=Fk-1;
开始将key值与第F(k-1)位置的记录进行比较(即mid=low+F(k-1)-1),比较结果也分为三种

1、key == arr[mid],mid位置的元素即为所求
2、key > arr[mid],low=mid+1,k-=2
low=mid+1:说明待查找的元素在[mid+1,high]范围内
k-=2:说明范围[mid+1,high]内的元素个数为n-(F(k-1))= Fk-1-F(k-1)=Fk-F(k-1)-1=F(k-2)-1个,所以可以递归的应用斐波那契查找
3、key < arr[mid],high=mid-1,k-=1
low=mid+1:说明待查找的元素在[low,mid-1]范围内
k-=1:说明范围[low,mid-1]内的元素个数为F(k-1)-1 个,所以可以递归 的应用斐波那契查找

关键点1:
关于斐波那契查找, 如果要查找的记录在右侧,则左侧的数据都不用再判断了,不断反复进行下去,对处于当众的大部分数据,其工作效率要高一些。所以尽管斐波那契查找的时间复杂度也为O(logn),但就平均性能来说,斐波那契查找要优于折半查找。可惜如果是最坏的情况,比如这里key=1,那么始终都处于左侧在查找,则查找效率低于折半查找。

关键点2:
1、折半查找是进行加法与除法运算的(mid=(low+high)/2)
2、插值查找则进行更复杂的四则运算(mid = low + (high - low) * ((key - a[low]) / (a[high] - a[low])))
3、而斐波那契查找只进行最简单的加减法运算(mid = low + F[k-1] - 1),在海量数据的查找过程中,这种细微的差别可能会影响最终的效率。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值