斐波那契(黄金分割法)查找算法
斐波那契算法基本介绍:
1.黄金分割点是把一条线段分割为两部分,是其中一部分与全长之比等于另一部分与这部分之比,取其前三位数的近似值为0.618。由于按此比例设计的造型十分美丽,因此称为黄金分割
2.斐波那契数列{1,1,2,3,5,8,13,21,34,55}发现斐波那契数列的相邻两个数的比例,无限接近黄金分格值0.618
3.斐波那契工作原理:斐波那契查找与二分查找和插入查找原理非常相似,仅仅改变了中间节点(mid)的位置,mid不在是中间或者是插值得到,而是位于黄金分割点附近,即mid=low=F(k-1)-1(F代表斐波那契数列)
对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值只要能
代码:
package com.gcy.searcch;
import java.util.Arrays;
/**
* 斐波那契查找算法
* @author Administrator
*
*/
public class FeibonaqiSearch {
public static int maxSize=20;
public static void main(String[] args) {
int[] arr= {1,8,10,89,1000,1234};
System.out.println("所要查找的数据的下标值index="+feiSearch(arr,1234));
}
/**
* 得到一个斐波那契数列
* 使用非递归方式
* @return
*/
public static int[] fei() {
int [] f=new int[maxSize];
f[0]=1;
f[1]=1;
for(int i=2;i<maxSize;i++) {
f[i]=f[i-1]+f[i-2];
}
return f;
}
/**
* 斐波那契查找算法
* @param arr
* @param key要查找的关键字
* @return返回对应 的下标值
* */
public static int feiSearch(int[] arr,int key) {
int low=0;
int high=arr.length-1;
int k=0;//表示斐波那契数分割数的下标值
int mid=0;
int[] f=fei();//调用斐波那契数列
//获取斐波那契分割数值的下标
while(high>(f[k]-1)) {
k++;
}
//因为f[k]值可能大于a的长度,因此需要使用Arrays工具类,构造一个新法数组,并指向temp[],不足的部分会使用0补齐
int[] temp=Arrays.copyOf(arr, f[k]);
//实际需要使用arr数组的最后一个数来填充不足的部分
for(int i=high+1;i<temp.length;i++) {
temp[i]=arr[high];
}
//使用while循环处理,找到key值
while(low<=high) {
mid=low+f[k-1]-1;
if(key<temp[mid]) {//向数组的前面部分进行查找
high=mid-1;
/*
* 对k--进行理解
* 1.全部元素=前面的元素+后面的元素
* 2.f[k]=k[k-1]+f[k-2]
* 因为前面有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>temp[mid]) {//向数组的后面的部分进行查找
low=mid+1;
/**
* 对k-=2理解
* 1.全部元素=前面的元素+后面的元素
* 2.f[k]=k[k-1]+f[k-2]
* 3.因为后面有k-2个元素,所以可以继续拆分f[k-2]=f[k-3]+f[k-4]
* 4.即在f[k-2]前面进行查找k-=2
* 5.即在下次循环mid=[k-1-2]-1
*/
k-=2;
}else {//找到了
//需要确定返回的是哪个下标
if(mid<=high) {
return mid;
}else {
return high;
}
}
}
return -1;
}
}
结果截图: