import java.util.Arrays;
public class FibonacciSearch {
public static void main(String[] args) {
int[] arr = {1, 2, 4, 9, 19, 34};
int index = fibSearch(arr, 1);
if (index == -1) {
System.out.println("该数未找到!");
} else {
System.out.println("该数在第" + index + "位。");
}
}
/**
* 由斐波那契数列 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 = start + F(k-1)-1
* 当数组中元素的个数和斐波那契数列中元素的个数不相等时,采用“大于数组长度的最近一个斐波那契数值”
* 比如当前数组长度为6,斐波那契数列中大于6的最近元素为8
* 进行数值填充,将数组从6个元素填充到8个,采用第6个元素的值对不足的部分进行填充
*/
public static int fibSearch(int[] arr,int value) {
int start = 0;
int end = arr.length - 1;
int mid = 0;
// 斐波那契分割点的下标
int k = 0;
// 获取斐波那契数列
int[] f = fibonacci();
// 从第一个斐波那契数开始,通过比较获取到大于数组长度的最近一个斐波那契数值
// 比较的两个数都为下标,正常位置-1
while (end > f[k] - 1) {
k++;
}
// f[k]的值会大于arry的长度,构造一个f[k]数值长度的数组,不足的部分默认用0填充
int[] temp = Arrays.copyOf(arr, f[k]);
// 将不足的部分用arr数组最后的数填充
for (int i = end + 1; i < temp.length; i++) {
temp[i] = arr[end];
}
// 使用while循环,采用非递归的方式查找value
while (start <= end && value >= arr[0] && value <= arr[arr.length - 1]) {
mid = start + f[k - 1] - 1;
if (value < temp[mid]) {
end = mid - 1;
// f[k] = f[k-1] + f[k-2],前面有f[k-1]个元素,可以进行拆分:f[k-1] = f[k-2] + f[k-3]
// 在f[k-1]前继续查找,下次循环 mid = start + f[k-1 - 1] - 1
k--;
} else if (value > temp[mid]) {
start = mid + 1;
// f[k] = f[k-1] + f[k-2],后面有f[k-2]个元素,可以进行拆分:f[k-2] = f[k-3] + f[k-4]
// 在f[k-2]前继续查找,下次循环 mid = start + f[k-2 - 1] - 1
k -= 2;
} else {
// 正常情况返回mid,因为temp数组被补充过,原数组后面多了几个和end一样的元素,mid会超过数组的长度
// 要返回mid和end小的那个,避免空指针异常
if (mid <= end) {
return mid;
} else {
return end;
}
}
}
return -1;
}
// 使用非递归方法得到一个斐波那契数列
public static int[] fibonacci() {
int maxSize = 20;
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;
}
}
algorithm:斐波那契查找
最新推荐文章于 2025-05-09 17:11:59 发布