Fibonacci查找是二分查找的一个变体。
原本的二分查找是取中间一个元素进行比较,而Fibonacci查找是找黄金分割点处的元素进行比较。
为什么是黄金分割点处的呢,我们可以先写出一段Fibonacci数列看看:
f
1
=
1
,
f
2
=
1
,
f
3
=
2
,
f
4
=
3
,
f
5
=
5
,
f
6
=
8
,
f
7
=
13
,
f
8
=
21
f_1=1,f_2=1,f_3=2,f_4=3,f_5=5,f_6=8,f_7=13,f_8=21
f1=1,f2=1,f3=2,f4=3,f5=5,f6=8,f7=13,f8=21
可以发现前一项与后一项的比值是越来越逼近0.618的。
所以假设我们有从21个数里查找一个数,就可以选择第8位位中间一位。
因为:
f
(
k
)
=
f
(
k
−
1
)
+
f
(
k
−
2
)
f(k)=f(k-1)+f(k-2)
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]+1
f(k)−1=[f(k−1)−1]+[f(k−2)−1]+1
图源自百度百科
#include<iostream>
#include<vector>
using namespace std;
int main()
{
//初始化数组和要查找的数
vector<int> arr = {12, 15, 21, 36, 42, 42, 56, 68, 81, 89, 94};
int n;
cout << "请输入要查找的数:" << endl;
cin >> n;
//为该数组建立相应的Fibonacci数列,数列的最后一位减一要大于等于数组长度才行
vector<int> Fib = {1, 1, 2};
int Fib_Most_Right_Index = Fib.size() - 1;
while (arr.size() > Fib[Fib_Most_Right_Index]-1)
{
Fib.push_back(Fib[Fib_Most_Right_Index - 1] + Fib[Fib_Most_Right_Index - 2]);
Fib_Most_Right_Index++;
}
int lo = 0;
int hi = arr.size();//遵循STL的迭代器超尾原则
int mi;
Fib_Most_Right_Index--;//先减一,为第一次去中间值做好准备
while (lo != hi)
{
mi = lo + Fib[Fib_Most_Right_Index--] - 1;//减一为下一次取中间值做准备
if (n < arr[mi])
hi = mi;
else if (n > arr[mi])
lo = mi + 1;
else
{
cout << "找到了,在第" << mi <<"位.";//当有多个命中者时不能保证输出的秩是最大的。
break;
}
}
}