1、Fibonacci数列
“有小兔一对,若等二月它们成年,第三月生下一对小兔,以后每月生产一对小兔,而所生小兔亦在第二月成年,第三月生产另一对小兔,以后亦每月生产小兔一对。假定每生产一对小兔,必为一雌一雄,且均无死亡,试问一年后共有小兔几对?
分析:首先观察一下头七个月的情况,为此引入下述记号,用 表示原来的一对小兔, ( =1,2……12)表示 第 个月生的一对小兔子, 表示第 对小兔子两个月以后又生的第 对小兔子,依次类推如表。
月份 |
| 对数 |
1 |
| 1 |
2 |
| 1 |
3 |
| 2 |
4 |
| 3 |
5 |
| 5 |
6 |
| 8 |
7 |
| 13 |
从表中可知七月份共有兔子13对;还可看出,从三月份开始,每月的兔子总数恰好等于它前面两个月的兔子总数之和。按这规律可写出数列1、1、2、3、5、8、13、21、34、55、89、144可见一年后共有兔子144对。我们这道题运用的是初等数学的归那法,通过对问题的分析列表并计算得出结论。
这是一个有限数列,按上述规律写出无限数列就叫做Fibonacci数列(这是为了纪念兔子繁殖问题的创始人意大利数学家裴波那契),其中的每一项叫做Fibonacci数。若令 此数列有下面的递推关系:
,
与Fibonacci数列紧密相关的一个重要极限是 ,这恰好是黄金分割比。除了与黄金分割有联系外,Fibonacci数列还出现在为数众多的领域,如某些叶子的排列,某些花的花瓣数,另外蜜蜂的家谱、钢琴音阶的排列也有该数列的特点。
2、Fibonacci二叉树的形成
1.以数据个数N来决定Fibonacci为K阶(k-order)
j=0 Fib(0)=0
j=1 Fib(1)=1
j=2 Fib(2)=1
j=3 Fib(3)=2
j=4 Fib(4)=3
……
j=N Fib(N)= Fib(N-1)+Fib(N-2)
设计一最小的k值,使得Fib(k+1)>N+1
2.K=0或k=1则表示Fibonacci只有一个结点,其余别无它物。
3.k>=2,则表示Fibonacci的根为Fib(k),左子树为(k-1)阶Fibonacci树(其根为Fib(k-1),右子树为(k-2)阶Fibonacci树(其根为Fib(k)+Fib(k-2)),上面的算法适用于N+1值为Fibonacci树,若N+1不为Fibonacci树,则找出M使得Fib(k)<N+1,再依上述算法建立Fibonacci树,最后把Fibonacci树的各结点数据减去M,就可以了。
3、Fibonacci差值原则
(1)左子树为负,右子树为正。
(2)如图所示:
步骤:
假设数据个数有n个且n比某一Fibonacci数小,满足下列的运算式,如下所示:
Fa>=n+1
则Fa-1就是这棵Fibonacci树的树根,而Fa-3则是开始的差值。如果我们要查找一个值key。首先我们比较数组索引和key,而得到下列的三种情况,如下所示:
1. 当key比较小,则我们查找1到Fa-1-1的数据。
2. 当key比较大,则我们查找Fa-1+1到Fa-1的数据。
3. 当key与数组索引Fa-1的值相等,表示查找成功。
4. 继续上述的步骤直到找到键值或Fibonacci树的差值为零。
C语言程序
fib[]={0,1,1,2,3,5,8,13,21,34,……}
int fib_search(int n,int key)
{ int index,mid fn1,fn2,temp;
for(index=0; fib[index]<n+1;index++);
mid=fib[index-1];
fn1=fib[index-2];
fn2=fib[index-3];
while(mid!=0){
if(key<data[mid].key)
if (fn2<=0)
mid=0;
else{
mid=mid-fn2;
temp=fn1;
fn1=fn2;
fn2=temp-fn2;}
}
else if(key>data[mid-1].key)
if(fn1<=1)
mid=0;
else{
mid=mid+fn2;
fn1=fn1-fn2;
fn2=fn2-fn1;}
else
return --mid;
}
return -1;
}
例:利用斐波那契查找法查找某一数值数据
原始数据:34 16 27 9 75 42 82 95
排序后的数据:
d[1] d[2] d[3] d[4] d[5] d[6] d[7] d[8]
9 16 27 34 42 75 82 95
利用算法规则,生成斐波那契树,如图所示:
比如要查找key=34,此时从树根开始比较:
(1) 当key>树根时,往右子树根开始比较;
(2) 当key<树根时,往左子树根开始比较;
(3) 当key=树根时,表示数据找到。
过程如下:
(1) key=34<82,往左子树查找->第一次;
(2) key=34<42,往左子树查找->第二次;
(3) key=34>27,往右子树查找->第三次;
(4) key=34,数据找到->第四次。
共查找四次
效率:
斐波那契查找与折半查找的时间复杂度间同为O(log2(log2n)),平均情况下,斐波那契查找优于折半查找,但最坏情况下则差于折半查找。斐波那契查找优点是只有加、减运算。折半查找有除法运算。缺点是每次必须计算下个级数。