斐波那契數列,指的是這樣一個數列:1、1、2、3、5、8、13、21...,除第1,2位的數為1外,其他數為前兩位數字的相加之和。
1.斐波那契數列與經典兔子繁殖問題
一般而言,兔子在出生兩個月后,就有繁殖能力,一對兔子每個月能生出一對小兔子來。如果所有兔都不死,那么在有1個月大的一對兔子的條件下一年以后可以繁殖多少對兔子?
我們可以分析一下。
第一個月一對兔子A生出一對小兔B。
第二個月還是原來的一對兔子A生出一對小兔C。
第三個月A生出一對小兔D,B生出一對小兔E。
第四個月A生出一對小兔F,B生出一對小兔G,C生出一對小兔H。
依次類推......如下表所示:
月份 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
每個月新出生的兔子對數 | 1 | 1 | 2 | 3 | 5 | 8 | 13 | 21 | 34 | 55 | 89 | 144 |
一年后繁殖的兔子對數量為:1+1+2+3+5+8+13+21+34+55+89+144
2.C語言使用遞歸來實現斐波納契數列

long fibonacci(int n);

#include <stdio.h> #include <stdlib.h> #include "fibonacci.h"
int main(void) { int n; long result; scanf("%d",&n); result=fibonacci(n); printf("%ld",result); return EXIT_SUCCESS; } long fibonacci(int n) { if( n>0 && n<=2 ) return 1; else
return fibonacci(n-1)+fibonacci(n-2); }
遞歸帶來的好處是使算法變得更加簡明,可讀性高。然而,使用遞歸也帶來了額外的內存開銷.可以考慮使用迭代實現斐波那契。
3.C語言使用迭代來實現斐波那契數列

#include <stdio.h> #include <stdlib.h> #include "fibonacci.h"
int main(void) { int n; long result; scanf("%d",&n); result=fibonacci(n); printf("%ld",result); return EXIT_SUCCESS; } long fibonacci(int n) { long result,previous_result,temp; result = previous_result =1; while(n>2) { temp = result; result += previous_result; previous_result = temp; n -= 1; } return result; }
原先自己的第一個思路是使用一個long數組存放斐波那契數列,在最后的第n位再把前兩項的數字相加返。但這樣做的話會浪費掉很多用不到的數組內存,所以改進為使用3個變量,一個記錄前一個結果,一個記錄當前結果,一個做為中間的temp變量,作為一個交換的介體。
4.斐波那契查找
斐波那契數列又稱為黃金分割數列。為什么叫做黃金分割數列呢?理由是當n趨近於無窮大的時候,后一項和前一項的比值越來越接近黃金分割1.618. 3/2=1.5,5/3=1.666,8/5=1.6,13/8=1.625...
數學背景:數字0.618…更為數學家所關注,它的出現,不僅解決了許多數學難題(如:十等分、五等分圓周;求18度、36度角的正弦、余弦值等),而且還使優選法成為可能。優選法是一種求最優化問題的方法。如在煉鋼時需要加入某種化學元素來增加鋼材的強度,假設已知在每噸鋼中需加某化學元素的量在1000—2000克之間,為了求得最恰當的加入量,需要在1000克與2000克這個區間中進行試驗。通常是取區間的中點(即1500克)作試驗。然后將試驗結果分別與1000克和2000克時的實驗結果作比較,從中選取強度較高的兩點作為新的區間,再取新區間的中點做試驗,再比較端點,依次下去,直到取得最理想的結果。這種實驗法稱為對分法。但這種方法並不是最快的實驗方法,如果將實驗點取在區間的0.618處,那么實驗的次數將大大減少。這種取區間的0.618處作為試驗點的方法就是一維的優選法,也稱0.618法。實踐證明,對於一個因素的問題,用“0.618法”做16次試驗就可以完成“對分法”做2500次試驗所達到的效果。因此大畫家達·芬奇把0.618…稱為黃金數。

#include <stdio.h>
#define MAX_SIZE 30
int fibonacci(int n); int main (void) { /*准備工作*/
int n,i,key; printf("Please input n:"); scanf("%d",&n); int list[MAX_SIZE]; printf("Please input your sorted array:"); for(i=1 ; i<=n ;i++) { scanf("%d",&list[i]); } printf("Please input the key:"); scanf("%d",&key); /*比較找到不小於n的斐波那契數的位置*/
int k = 1; while(n>fibonacci(k)) { k++; } /*在n的個數不足找到的斐波那契數,用list【n】補齊*/
for(i=n+1; i<=fibonacci(k); i++) { list[i]=list[n]; } /*定義key的位置*/
int pos = -1; int low,high,mid; low = 1; high = n; while(low <= high) { mid =low + fibonacci(k-1) -1; if(key < list[mid]) { high=mid - 1; k = k-1; } else if(key > list[mid]) { low=mid + 1; k = k-2; } else { if(mid<n) { pos = mid; break; } else { pos = n; break; } } } printf("The result position is %d.",pos); return 0; } int fibonacci(int n) { int result,previous_result,temp; result = previous_result = 1; while(n>2) { temp=result; result+=previous_result; previous_result=result; n--; } return result; }
對斐波那契查找可能存在兩個比較難理解的地方。
(1)
/*在n的個數不足找到的斐波那契數,用list【n】補齊*/
for(i=n+1; i<=fibonacci(k); i++) { list[i]=list[n]; }
由於斐波那契查找是基於斐波那契數列的查找,要求有序表的個數必須是存在於斐波那契數列中的數,所以在數不足的情況下,如n=10,fibonacci(7)=13 > 10,必須將有序表的個數擴增到等於斐波那契數,則list[11]=list[12]=list[13]=list[n]。
(2)
if(key < list[mid]) { high=mid - 1; k = k-1; } else if(key > list[mid]) { low=mid + 1; k = k-2; }
在key<list[mid] 的情況下 k=k-1,ket > list [mid] 的情況下 k=k-2。這又是為什么呢?
對於斐波那契查找,分割是從mid =low + fibonacci(k-1) -1 開始的,現在數組的長度為fibonacci(k),mid 將數組分為兩個部分,前一部分為[1,mid],長度為fiboncaai(k-1),則后一部分的長度為fibonacci(k)-fibonacci(k-1),根據斐波那契的性質,f(k) - f(k-1) = f(k-2),則后一部分的長度為fibonacci(k-2),所以當key > list[mid] 的時候 k = k - 2。
斐波那契的時間復雜度也為O(log n),相對與擇半查找進行加法與除法運算(mid=(low + high)/2 ),斐波那契查找只是最簡單加減法運算( mid = low + fibonacci(k-1) -1 ),在海量數據的查找過程中,這種細微的差別可能會影響最終的查找效率。