讀昨天剛買的《android應用效能優化》,第一章介紹了斐波那契數列的實現及優化,這是演算法方面的問題。
斐波那契數列,又稱**分割數列,指的是這樣乙個數列:0、1、1、2、3、5、8、13、21、……在數學上,斐波納契數列以如下被以遞迴的方法定義:f0=0,f1=1,fn=f(n-1)+f(n-2)(n>=2,n∈n*)
書中介紹了4種實現,頭兩種是遞迴,後面兩種是迭代。當然迭代更好,因為遞迴效率低下,可能導致棧溢位。
public static long computerecursively(int n)
第一種很好理解,不用多說,後面的三種,很費力的研究了許久。
第二種是對第一種的優化,見下,每次呼叫少遞迴呼叫一次:
public static long computerecursivelywithloop(int n) while(n>1);
return result;
} return n;
}
分析:看起來就像是從第n-2個值開始累加到第乙個,在額外加上個1,就是第n個值。
f(n) = f(n-2) + f(n-1)每次都把上次分解得到的較大的乙個(即每行的最後乙個)進行再分解,得到f(n) = sum(f(n-2) + ... +f(0)) + 1
= f(n-2) + f(n-3) + f(n-2)
= f(n-2) + f(n-3) + f(n-4) + f(n-3)
= f(n-2) + f(n-3) + f(n-4) + (f(n-5)+f(n-4))
= f(n-2) + f(n-3) + f(n-4) + f(n-5) + f(n-6) + f(n-5)
= ...
= f(n-2) + f(n-3) + ... + f(2) + f(3)
= f(n-2) + f(n-3) + ... + f(2) + f(1) + f(2)
= f(n-2) + f(n-3) + ... + f(2) + f(1) + f(0) + f(1)
= sum(f(n-2) + ... + f(0)) + 1
剩下的兩種迭代實現的方法也是這個求和的原理,方法3如下:
public static long computeiteratively(int n)while(--n>1);
return b;
} return n;
}
0 1 2 3 4 5 6 7 8
0 1 1 2 3 5 8 13 21
0 a b
1 a b
2 a b
3 a b
4 a b
5 a b
6 a b
7 a b
經歷n-1次迴圈, f(n) = b
方法4每次迭代計算兩項,迭代總數與方法3相比少了一半:
根據n奇偶判斷初值,如果n是奇數,則a=0, b=1;如果n是偶數則a=1,b=1
public static long computeiterativelyfaster(int n)
return b;
} return n;
}
自己根據方法4寫了自以為更容易理解的:
0 1 2 3 4 5 6 7 8
0 1 1 2 3 5 8 13 21
0 a b
1 a b
2 a b
3 a b
4 a b
經歷n/2次迴圈, 如果n為奇數,f(n)=b; 如果n為偶數,f(n)=a
public static long computeiterativelyfaster2(int n)
}if(evenodd==0)else
} return n;
}
關於溢位:
long型有64位,除去第一位是符號位,最大值為9223372036854775807。
可容納的最大的斐波那契數是7540113804746346429,即第92項。
寫的方法裡做了檢測,當溢位的時候,跳出,檢視當前的a、b值,及迴圈次數。
執行結果:
當n=30的時候,
long_max:9223372036854775807
f[30]
832040
5ms832040
4ms832040
0ms832040
0ms832040
0ms當n=100的時候(注釋掉前兩個遞迴的方法,費時太長,比較的都是迭代的方法)
long_max:9223372036854775807
f[100]
3736710778780434371
0ms3736710778780434371
0msn:4,a:7540113804746346429,b:-6246583658587674878,cnn:46
7540113804746346429
0ms此時,迭代所用時間都在1ms之內。
自己寫的方法裡檢測到b溢位了,此時迴圈次數是46次,意味著最大支援的是2倍的92項值7540113804746346429。
3736710778780434371是已經溢位了之後,丟失了符號位得到的數值。
溢位解決,見第二章biginteger
斐波那契數列的演算法研究
背景 假定你有一雄一雌一對剛出生的兔子,它們在長到乙個月大小時開始交配,在第二月結束時,雌兔子產下另一對兔子,過了乙個月後它們也開始繁殖,如此這般持續下去。每只雌兔在開始繁殖時每月都產下一對兔子,假定沒有兔子死亡,在一年後總共會有多少對兔子?在一月底,最初的一對兔子交配,但是還只有1對兔子 在二月底...
斐波那契數列 斐波那契數列python實現
斐波那契數列 fibonacci sequence 又稱 分割數列 因數學家列昂納多 斐波那契 leonardoda fibonacci 以兔子繁殖為例子而引入,故又稱為 兔子數列 指的是這樣乙個數列 1 1 2 3 5 8 13 21 34 在數學上,斐波納契數列以如下被以遞推的方法定義 f 1 ...
迴圈斐波那契數列 斐波那契數列應用
什麼是斐波那契數列 斐波那契數列指的是這樣乙個數列 1,1,2,3,5,8,13,21,34,55,89,144 這個數列從第3項開始,每一項都等於前兩項之和 台階問題 有一段樓梯有10級台階,規定每一步只能跨一級或兩級,要登上第10級台階有幾種不同的走法?這就是乙個斐波那契數列 登上第一級台階有一...