斐波那契(黄金分割)查找

  1. 斐波那契数列:1 1 2 3 5 8 13 21 .。。。

  2. 黄金分割点是指把一条线段分割成俩部分,使其中一部分与全长之比等于另一部分与这部分之比。取其前三位数字的近似值是0.618,由于按比例设计地造型十分美丽,因此被叫黄金分割,也成为中外比

  3. 在这里插入图片描述

  4. 对F(k-1)-1的理解:
    1)由斐波那契数列 F[k]=F[k-1]+F[k-2] 的性质,可以得到 (F[k]-1)=(F[k-1]-1)+(F[k-2]-1)+1 。该式说明:只要顺序表的长度为 F[k]-1,则可以将该表分成长度为 F[k-1]-1 和 F[k-2]-1 的两段,即如上图所示。从而中间位置为 mid=low+F(k-1)-1
    2)类似的,每一子段也可以用相同的方式分割
    3)但顺序表长度 n 不一定刚好等于 F[k]-1,所以需要将原来的顺序表长度 n 增加至 F[k]-1。这里的 k 值只要能使得 F[k]-1 恰好大于或等于 n 即可,由以下代码得到,顺序表长度增加后,新增的位置(从 n+1 到 F[k]-1 位置),都赋为 n 位置的值即可

public class Main{
	//构造一个斐波那契数列
	public static int[] fib() {
		int[] f=new int[max];
		f[0]=1;
		f[1]=1;
		for(int i=2;i<max;i++) {
			f[i]=f[i-1]+f[i-2];
		}
		return f;
	}
	//编写斐波那契数列查找算法
	//使用非递归的方式编写算法
	/**
	 * 
	 * @param a	数组
	 * @param key	我们需要查找的关键码(值)
	 * @return	返回对应的下表,如果没有则-1
	 */
	public static int fibSearch(int[] a,int key) {
		int low=0;
		int high=a.length-1;
		int k=0;//表示斐波那契分割数值的下标
		int mid=0;//存放mid值
		int f[]=fib();//获得斐波那契数列
		//获得到斐波那契分割数值的下标
		while(high>f[k]-1) {
			k++;
		}
		//因为f[k]可能大于a的长度,因此我们需要使用Arrays类,构造一个新的数组。并指向tmp[]
		//不足的部分会使用0填充
		int[] tmp=Arrays.copyOf(a, f[k]);
		//实际上需求使用a数组最后的数填充tmp
		//举例:temp = {1,8, 10, 89, 1000, 1234, 0, 0}
		//=> {1,8, 10, 89, 1000, 1234, 1234, 1234,}
		for(int i=high+1;i<tmp.length;i++) {
			tmp[i]=a[high];
		}
		//使用while来循环处理,找到我们的数key
		while(low<=high) {
			mid=low+f[k-1]-1;
			if(key<tmp[mid]) {//向左查
				high=mid-1;
				//为什么要k--
				//全部元素=前面元素+后面元素
				//f[k]=f[k-1]+f[k-2]
				//因为前面有f[k-1]个元素,所以可以继续拆分f[k-1]=f[k-2]+f[k-3]
				//即在f[k-1]的前面继续查找k--
				//即下次循环mid=f[k-1-1]-1
				k--;
			}else if(key>tmp[mid]) {//向右找
				low=mid+1;
				//为什么是k-=2;
				//全部元素=前面元素+后面元素
				//f[k]=f[k-1]+f[k-2]
				//因为前面有f[k-2]个元素,所以可以继续拆分f[k-2]=f[k-3]+f[k-4]
				//即在f[k-2]的前面继续查找k-=2
				//即下次循环mid=f[k-1-2]-1
				k-=2;
			}else {//找到
				//确定返回的是哪个下标
				if(mid<=high) {
					return mid;
				}else {
					return high;
				}
			}
		}
		return -1;
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值