一、什么是斐波那契查找
斐波那契搜索就是在二分查找的基础上根据斐波那契数列进行分割的。在斐波那契数列找一个等于略大于查找表中元素个数的数F[n], 将原查找表扩展为长度为F[n](如果要补充元素,则补充重复最后一个元素,直到满足F[n]个元素),完成后进行斐波那契分割,即F[n]个元素分割为前半部分F[n-1]个元素,后半部分F[n-2]个元素,找出要查找的元素在那一部分并递归,直到找到。
二、算法要求
查找表是顺序存储的有序表
三、查找过程
- 斐波那契查找原理与前两种相似,仅仅改变了中间结点(mid)的位置,mid不再是中间或插值得到,而是位于黄金分割点附近,即mid=low+F(k-1)-1(F代表斐波那契数列),如下图所示
- 对F(k-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
-
类似的,每一子段也可以用相同的方式分割
-
顺序表长度n不一定刚好等于F[k]-1,所以需要将原来的顺序表长度n增加至F[k]-1。这里的k值只要能使得F[k]-1恰好大于或等于n即可,由以下代码得到,顺序表长度增加后,新增的位置(从n+1到F[k]-1位置),都赋为n位置的值即可。
四、代码实现
import java.util.Arrays;
public class FibonacciSearch {
public static void main(String[] args) {
int[] array = {1,8,10,89,1000,2000};
System.out.println("index="+fibonacciSearch(array,-1));
}
/**
* @return 斐波那契数列
*/
public static int[] fibonacciSequence(int maxSize) {
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 arrays 传入数组
* @param value 待搜索的值
* @return 下标
*/
public static int fibonacciSearch(int[] arrays, int value) {
int left = 0;
int right = arrays.length - 1;
int mid = 0;
//存放斐波那契数列
int[] fibArray = fibonacciSequence(10);
//表示斐波那契分割数值的下标
int fibIndex = 0;
//获取到斐波那契分割数值的下标
while (right > fibArray[fibIndex] - 1) {
fibIndex++;
}
//fibArray[fibIndex]的值可能大于a的长度,因此需要构建一个新数组,不足的部分会使用0填充
int[] temp = Arrays.copyOf(arrays, fibArray[fibIndex]);
//将新填充的内容替换为最后的数
//例:temp = {1,3,4,6,9,11,0,0} => {1,3,4,6,9,11,11,11}
for (int i = right + 1; i < temp.length; i++) {
temp[i] = arrays[right];
}
//使用while来循环处理,找到value,前提是左指针在右指针前边
while (left <= right) {
mid = left + fibArray[fibIndex - 1] - 1;
//当查找的值小于当前值时应该向数组的前边遍历
if (value < temp[mid]) {
right = mid - 1;
//斐波那契数向前移一位
fibIndex--;
}
//当查找的值小于当前值时应该向数组的后边遍历
else if (value > temp[mid]) {
left = mid + 1;
fibIndex -= 2;
} else {
if (mid <= right) {
return mid;
} else {
return right;
}
}
}
return -1;
}
}