斐波那契查找算法:前提是一个有序数组。
斐波那契数列:1,1,2,3,5,8,13,21。。。。。。
主要思想:通过斐波那契数列找到数组黄金分割点附近的下标,即mid。
根据上图所示:假设有一个数组,数组里面的元素有F[k]-1个,这个数组被分成了三份:F[k-1]-1,1和F[k-2]-1这三份(mid点是一个元素,长度为1)。
根据斐波那契数列的公式:
F[k]=F[k-1]+ F[k-2],将这个公式变型为F[k]-1=F[k-1]-1+ F[k-2]-1+1。
根据斐波那契查找法,mid的选择方法为mid = low+F[k-1]-1,使mid位于黄金分割点附近。
例如上图所示:low=0,F[k-1]-1=4,mid= 4。所以k=4时:4=0+5-1。
当数组的元素为{1,2,3,4,5,6}时,为了满足斐波那契数列,数组的长度需要满足:
While(array.Length > F[k]-1){
K++;
}
K=0开始每次加1,直到F[k]-1的值大于或等于数组的长度为止。
因此,根据这个条件,上面的数组长度为6,在k=5时,F[5] – 1=7,数组需要正价长度及元素,将数组长度变为7,在后面赋值数据最后一个元素的值。
```package SearchTest;
import java.util.Arrays;
public class FibonacciSearchTest {
public static int max = 20;// 定义斐波那契数列的长度
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] arr = { 1, 8, 10, 89, 100, 123, 200 };
System.out.println(FibonacciSearch(arr, 123));
}
// 实现一个斐波那契数列的方法
// 1,1,2,3,5,8,13,21,34,55......
public static int[] Fibonacci() {
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;
}
// 实现斐波那契查找的步骤
public static int FibonacciSearch(int[] arr, int findVal) {
int low = 0;// 数据的左边下标
int high = arr.length - 1;// 数组的右边下标
int[] f = Fibonacci();// 将斐波那契数列传递给f数组
int k = 0;// 用来弥补F[k]-1余arr.Length的差距
int mid = 0;// 黄金分割点
// 判断数组的长度是否小于F[k]-1,如果小于就用k计数
// 这个地方是数组长度与斐波那契数列中的数据进行比较
// 因此,数组的长度是arr.Length,
while (arr.length > f[k] - 1) {// f[5] = 8,high = 5;
k++;// 直到找到一个k的值,可以使f[k]-1大于high时结束,k为斐波那契数列下标
}
// 这时需要填充数组arr,需要达到斐波那契数列的长度
// 但是arr得长度已经固定了,因此需要一个临时的数组
int[] tmp = Arrays.copyOf(arr, f[k] - 1);//
for (int i = high + 1; i < tmp.length; i++) {
tmp[i] = arr[high];
}
// 开始循环
while (low <= high) {
mid = low + f[k - 1] - 1;// 黄金分割点
if (findVal < tmp[mid]) {
high = mid - 1;
// 这个k=k-1可以理解为现在对新的数组进行查找,也是斐波那契数列,此时的数据长度为F[k-1]-1
// 现在可以令k-1=K,这样这个数组的长度可以写成F[K]-1,mid = low+F[K-1]-1即low+F[k-2]-1
k = k - 1;//
} else if (findVal > tmp[mid]) {
low = mid + 1;
// 这个k=k-2可以理解为现在对新的数组进行查找,也是斐波那契数列,此时的数据长度为F[k-2]-1
// 现在可以令k-2=K,这样这个数组的长度可以写成F[K]-1,mid = low+F[K-1]-1即low+F[k-3]-1
k = k - 2;
} else {// 由于数组后面的数据都是最后一个元素填充的,mid可能是那些填充数据的下标,因此需要比较与真实数组长度的大小
if (mid <= high) {
return mid;
} else {
return high;
}
}
}
return -1;
}
}