基本介绍
黄金分割点
黄金分割点是指把一条线段分割为两部分,使其中一部分与全长之比等于另一部分与这部分之比。取其前三位数字的近似值是0.618。由于按此比例设计的造型十分美丽,因此称为黄金分割,也称为中外比。这是一个神奇的数字,会带来意向不到的效果。
斐波拉契数列
斐波那契数列 {1, 1, 2, 3, 5, 8, 13, 21, 34, 55 } 发现斐波那契数列的两个相邻数的比例,无限接近黄金分割值0.618。
斐波那契查找和斐波那契数列有什么联系?

斐波那契查找原理与二分查找和插值查找相似,仅仅改变了mid的位置,mid不再是中间或插值得到,而是位于黄金分割点附近,即mid=left+F(k-1)-1
为什么是F(k)-1
F(k)-1 = F(k-1)-1 + F(k-2)-1 + 1, mid占一个位置,刚好mid前面一个子序列占F(k-1)-1,后面占F(k-2)-1,格式统一,在循环程序里使用起来就很方便。
排序流程
- 构建一个合适的斐波拉契数组
- 构建一个临时数组,长度是F(k)-1且刚好等于或大于原始数组长度
- 拷贝原始数组到临时数组,临时数组多出来的位置用原始数组最后一位填充
- mid值使用low+F(k-1)-1
- 比较arr[mid]和key
5.1 key>arr[mid], left=mid+1,k-=2, 因为在新的left到right区间元素个数为F(k-2)-1,所以这里要k-=2;
5.2 key<arr[mid], right=mid-1,k–, 因为在left到新的right区间元素个数为F(k-1)-1,所以这里k–;
5.3 key==arr[mid], return
代码实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
|
/**
* 构建斐波拉契数组
*
* @param size
* @return
*/
private static int[] buildFibonacciArr(int size) {
int[] f = new int[size];
f[0] = 0;
f[1] = 1;
for (int i = 2; i < size; i++) {
f[i] = f[i - 1] + f[i - 2];
}
return f;
}
/**
* 斐波拉契查找
*
* @param arr
* @param key
* @return
*/
public static int fibonacciSearch(int[] arr, int key) {
int left = 0, right = arr.length - 1;
// 1. 构建一个合适的斐波拉契数组
int[] f = buildFibonacciArr(20);
// 2. 构建临时数组
// 2.1 确定临时数组长度也就是确定k值
int k = 1; // 斐波拉契数组下标
while (arr.length > f[k] - 1) {
k++;
}
// 2.2 构建一个临时数组,长度是F(k)-1且刚好等于或大于原始数组长度,拷贝原始数组到临时数组
int[] temp = Arrays.copyOf(arr, f[k] - 1);
// 2.3 临时数组多出来的位置用原始数组最后一位填充
for (int i = right + 1; i < temp.length; i++) {
temp[i] = arr[right];
}
// 查找key所在位置
while (left <= right) {
int mid = left + f[k - 1] - 1;
if (key > arr[mid]) {
left = mid + 1;
k -= 2; // 因为在新的left到right区间元素个数为F(k-2)-1,所以这里要k-=2;
} else if (key < arr[mid]) {
right = mid - 1;
k--; // 因为在left到新的right区间元素个数为F(k-1)-1,所以这里k--;
} else {
if (mid < arr.length) {
return mid;
} else {
return arr.length - 1;
}
}
}
return -1;
}
|