使用Rust做斐波那契數列
用了Rust優化意識更強烈了,總想把代碼優化到極致
1、遞歸版本
fn fb(i: i32) -> i32 {
if i <= 0 {
panic!("索引要大於0");
}
return if i <= 2 { 1 } else { fb(i - 1) + fb(i - 2) };
}
2、非遞歸版本
fn fb_use_loop(mut n: i32) -> i32 {
if n <= 0 {
panic!("索引要大於0");
}
let mut p1 = 1;
let mut p2 = 0;
let mut now = 1;
while n > 0 {
now = p1 + p2;
p1 = p2;
p2 = now;
n -= 1;
}
return now;
}
3、利用編譯器檢查的unsigned版本
編譯器會自動檢查傳入的值,如果是負數就會報錯。嚴格意義上代碼還有一個小問題,那就是fb(0)會是1,斐波那契數列理論上是不存在0的,但是不影響其它的結果都是正確的。此外還有整數溢出錯誤,這個和之前的都存在,但是斐波那契增長還是挺快的,要避免這個問題似乎也沒有什麼意義,總有更大的數讓你溢出。如果是普通的題目,u32(4294967295)應該夠了。rust的這個 return if else語法糖真的很方便。
fn fb(i: u32) -> u32 {
return if i <= 2 { 1 } else { fb(i - 1) + fb(i - 2) };
}
fn fb_use_loop(mut n: u32) -> u32 {
let mut p1 = 1;
let mut p2 = 0;
let mut now = 1;
while n > 0 {
now = p1 + p2;
p1 = p2;
p2 = now;
n -= 1;
}
return now;
}
4、急速體驗
通過使用一個vector來對已經計算出來的斐波那契數列進行緩存。
struct Fb {
cache: Vec<usize>,
}
impl Fb {
fn new() -> Fb {
return Fb {
cache: vec![0, 1, 1],
};
}
fn at(&mut self, n: usize) -> usize {
return match self.cache.get(n) {
Some(num) => *num,
None => {
// None時n總是大於2的,因爲new中已經初始化了cache
let v = self.at(n - 1) + self.at(n - 2);
self.cache.push(v);
v
}
};
}
}
使用時只需要:
let mut fb_cached = Fb::new();
println!("{}", fb_cached.at(12));