Java算法总结(3)_斐波那契查找法

1、原理

   类似于二分法查找,它们的不同之处在于,斐波那契查找将查找点的对半选择改进为黄金分割点选择,所以又叫做黄金比例查找法;
在这里插入图片描述
其中 searchVal代表需要查找的值,fid是斐波那契数列;

2、基础知识
2.1 斐波那契数列

1,1,2,3,5,8,13,21…F(n-1),F(n),其一般表达式为F(n)=F(n-1)+F(n-2),其中F(1)=1,F(2)=1,中文解释即一个数字等于它前面两项之和;

2.2 黄金分割

证明:当n趋近无穷大时,F(N-1)/F(N)=0.618(黄金分割点);
在这里插入图片描述

3、算法特点

1、有序列表,同类有二分法插值法
  斐波那契数列的最大位置pos,先是由列表的长度len决定的,然后再角色互换来决定列表长度len;pos取值规则为fib[pos]>=len中的最小值,当列表的长度len小于fib[pos]的取值时,需要重建列表长度为fib[pos],并使用列表的原先最高位值a[len-1]填补增加的位置[len,fib[pos]-1];
2、黄金分割;
3、避免除法运算,在计算机中除法运算的占用资源比加减法高;
4、时间复杂度O(logn)

4、 图解

在这里插入图片描述

5、算法代码:
package xw.zx.algorithm.search;

public class FibSearch {
	private static final int FIB_SIZE=100;
	private int[] fibArr=new int[FIB_SIZE];
	public FibSearch() throws RuntimeException{
		super();
		this.fibArr = generatorFibArray(FIB_SIZE);
	}
	/**
	 * 构造斐波那契数列
	 * @param n
	 * @return
	 */
	private int[] generatorFibArray(int n) {
		if(n<1) {
			throw new RuntimeException("n值必须大于等于1");
		}
		int[]  fibArr=new int[n];
		fibArr[0]=1;
		fibArr[1]=1;
		for(int i=2;i<n;i++) {
			fibArr[i]=fibArr[i-1]+fibArr[i-2];
		}
		return fibArr;
	}
	/**
	 * 获取比iniArr的长度恰大一些的,斐波那契位置
	 * @param iniArr
	 * @return
	 */
	private int findMaxPos(int[] iniArr) {
		int pos=0;
		int len=iniArr.length;
		
		try {
			while(len>fibArr[pos]-1) {
				pos++;
			}
		} catch (Exception e) {
			
			throw new RuntimeException("斐波那契数列长度不够");
		}
		return pos;
	}
	/**
	 * 重建数组
	 * @param iniArr
	 * @param pos
	 * @return
	 */
	private int[] rebuildArr(int[] iniArr,int pos) {
		int[] arr=new int[fibArr[pos]];
		int len=iniArr.length;
		System.arraycopy(iniArr, 0, arr, 0, len);
		for (int i = len; i <= fibArr[pos]-1; i++) {
			arr[i] = iniArr[len-1];
		}
		return arr;
	}
	
	/**
	 * 斐波那契查找法,
	 * 
	 * @param arr
	 * @param searchVal
	 * @return
	 */
	public int fibSearch(int[] arr,int searchVal) {
		//初始化查询次数、下界low、上界high、数组原始长度len
		int count=0,low =0,high=arr.length-1,len=arr.length;
		int mid,guess,pos;
		//获取斐波那契最大位置;
		pos=findMaxPos(arr);
		//重建原始数组
		arr=rebuildArr(arr,pos);
		while(low<=high) {
			//low+黄金分割点,之所以减1的原因是数组的开始索引从0开始,而斐波那契数列以1开始;
			 mid=low+fibArr[pos-1]-1;			
			 guess=arr[mid];
			 System.out.println("guess:"+guess);
			 count++;
			 //找到值
			 if(guess==searchVal) {				
				 if(mid<len-1) {
					 System.out.println("下标:"+mid );
				 }else {
					 //存在mid超出原始数组长度的情况,因为原始数组扩容过
					 System.out.println("下标:"+(len-1));
				 }
				 return count; 
			 }
			 //定界	 
			 if(guess>searchVal) {
				 high=mid-1;
				 /**
				  * 之所以减1,是因为数组的剩余查找部分[low,high],在下一次迭代中长度变为fib[pos-1],
				  * 准确地讲,剩余长度应该为fib[pos-1]-1,因为我们将high设置成了mid-1;
				  */
				 pos=pos-1;
			 }else {
				 low=mid+1;
				 /**
				  * 之所以减2,是因为数组的剩余查找部分[low,high],在下一次迭代中长度变为fib[pos-2],
				  * 准确地讲,存在剩余长度为fib[pos-2]-1的情况,因为我们将high设置成了mid-1;
				  */
				 pos=pos-2;
			 }
		}
		return -1;
	}
	
	public static void main(String[] args) {
		 int cnt;
		 //原始数组
		 int[] iniArr= {3,6,8,9,13,16,20,21,25};
		 //查找值
		 int searchVal=8;
		 FibSearch fib=new FibSearch();
		 //调用斐波那契查找法
		 cnt=fib.fibSearch(iniArr, searchVal);
		 System.out.println("查找次数: "+cnt);
		 
	}
}

输出结果:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值