『アルゴリズムとデータ構造』を Rust で実装してみるシリーズ。4章の再帰と分割統治法。
前回 → https://quantized-cube.com/rust-recursive-02
今回はフィボナッチ数列。
use proconio::input;
fn input(use_default_values: bool) -> usize {
if use_default_values {
let n = 49;
return n;
} else {
println!("Input n:");
input! {
n: usize,
}
return n;
}
}
/// フィボナッチ数列を求める再帰関数
pub fn code_4_5(n: u64) -> u64 {
match n {
// ベースケース
0 => 0,
1 => 1,
// 再帰呼び出し
_ => code_4_5(n - 1) + code_4_5(n - 2),
}
}
/// フィボナッチ数列を求める再帰関数の
/// 再帰呼び出しの様子
pub fn code_4_6(n: u64) -> u64 {
println!("code_4_6({}) を呼び出しました", n);
match n {
// ベースケース
0 => 0,
1 => 1,
// 再帰的に答えを求めて出力する
_ => {
let result = code_4_6(n - 1) + code_4_6(n - 2);
println!("{} 項目 = {}", n, result);
result
}
}
}
/// フィボナッチ数列を for 文による反復で求める
pub fn code_4_7() {
let mut f: Vec<u64> = vec![0; 50];
f[1] = 1;
for n in 2..50 {
f[n] = f[n - 1] + f[n - 2];
println!("{} 項目 = {}", n, f[n]); // f[49] = 7778742049
}
}
fn fibo(n: usize, memo: &mut Vec<i64>) -> i64 {
// ベースケース
if n == 0 {
return 0;
} else if n == 1 {
return 1;
}
// メモをチェック (すでに計算済みならば答えをリターンする)
if memo[n] != -1 {
return memo[n];
}
// 答えをメモ化しながら,再帰呼び出し
memo[n] = fibo(n - 1, memo) + fibo(n - 2, memo);
return memo[n];
}
/// フィボナッチ数列を求める再帰関数をメモ化
pub fn code_4_8(use_default_values: bool) -> i64 {
// 入力
let n = input(use_default_values);
// fibo(n) の答えをメモ化する配列
// メモ化用配列を -1 で初期化する
let memo: &mut Vec<i64> = &mut vec![-1; n + 1];
// fibo(49) をよびだす
fibo(49, memo);
// memo[0], ..., memo[49] に答えが格納されている
for n in 2..50 {
println!("{} 項目 = {}", n, memo[n]);
}
memo[n]
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn code_4_5_works() {
assert_eq!(code_4_5(6), 8);
}
#[test]
fn code_4_6_works() {
assert_eq!(code_4_6(6), 8);
}
#[test]
fn code_4_8_works() {
assert_eq!(code_4_8(true), 7778742049);
}
}
GitHub のリポジトリはこちら https://github.com/quantized-cube/book_algorithm_solution_rust
コメント