Rust 实现斐波那契数列——Rust语言基础09


本文是为回顾之前内容所做的一个小练习。使用 Rust 实现斐波那契数列。

1. 题目

1、输出几个斐波那契数列,让用户了解斐波那契数列的基本规律;(0、1、1、2、3、5、8、13、21、34
2、要求用户输入需要查看的斐波那契数的索引号,并输出对应索引的斐波那契数。(如:输入 0,输出 0;输入 1,输出 1;输入 2,输出 1;输入 6,输出 8
3、同时校验用户输入是否正确。

2. 分析

分析1:
这个很简单,我们只需要将基本样例简单的打印出来就好。

分析2:
相信斐波那契数列大家也已经熟悉的不能再熟悉了,但仍需提醒的一点是,Fibonacci 数列的第 0 项为 0(第一个数,是第零项,而非第一项,即索引号为 0)。
获取从终端上的标准输入,并将其转换为整型数字(这一点之前已经可以做到了)。再根据斐波那契数列的规律将对应索引的值打印即可。
分析3:
确保用户输入的是正确的索引号,而非负值、零、小数和其它各种符号。

3. 实现

在此之前请各位根据题目先自己完成,然后用各位写的代码与笔者写的代码对比,若觉得笔者代码需要改进的地方,还请不吝赐教,欢迎指出,我会非常感谢的!!!

和往常一样,首先创建新的项目:

imaginemiracle:rust_projects$ cargo new fibonacci
imaginemiracle:rust_projects$ cd fibonacci/
imaginemiracle:fibonacci$ ls
Cargo.lock  Cargo.toml  src  target

3.1. 代码展示

如下提供两种实现方法,一种是以常规的方式实现,另一种使用递归的方法实现。
(1)常规方法实现:
笔者实现的代码如下:

use std::io;

fn fibonacci_demo() {
    println!("The Fibonacci sequence demo: 0、1、1、2、3、5、8、13、21、34、...");
}

fn get_input_number() -> usize {
    loop {
        let mut number = String::new();

        io::stdin()
            .read_line(&mut number)
            .expect("Failed to read line.");

        let number: usize = match number.trim().parse::<usize>() {
            Ok(num) => num,

            Err(_) => {
                println!("Please enter the correct index(like 1,2,3,...)!");

                continue;
            }
        };

        return number;
    }
}

fn overflow_check(num1: usize, num2: usize) -> bool {
    if num1 > (usize::MAX / 2) && num2 > (usize::MAX / 2) {
        return false;
    } else if num1 > (usize::MAX / 2) || num2 > (usize::MAX / 2) {

        let checker: isize = num1 as isize - (usize::MAX / 2) as isize ;

        let checker1: usize = num2 - (usize::MAX / 2);

        let checker: isize = checker + checker1 as isize;

        if checker > 0 { return false } else { return true }
    } else {
        return true;
    }
}

fn fibonacci(index: usize) -> usize {
    let mut f0: usize = 0;
    let mut f1: usize = 1;
    let mut result: usize = f0;

    for _i in 1..index {

        if overflow_check(f0, f1) {

            result = f0 + f1;
            f0 = f1;
            f1 = result;
        } else {

            println!("It's too big!!!");
            return 0;
        }

    }

    match index {
        0 => 0,
        1 => 1,
        _ => result
    }
}

fn main() {

    fibonacci_demo();

    println!("Please enter the index of the fibonacci sequence:");

    let index: usize = get_input_number();

    println!("The {index}th Fibonacci number: {}", fibonacci(index));
}

(2)递归方法实现:
使用递归方式实现,与上面代码不同之处在于 fibonacci 函数的实现,因此下面只展示 fibonacci 函数,其余代码与上文相同。

fn fibonacci(index: usize) -> usize {

    if index < 2 {
        return 1 * (1 & index);
    }
	// 无数据溢出检查的返回,输出过大会报 “栈溢出” 错误
    return fibonacci(index - 1) + fibonacci(index - 2);
	// 有数据溢出检查
    /*
    if overflow_check( fibonacci(index - 1), fibonacci(index - 2) ) {
        return fibonacci(index - 1) + fibonacci(index - 2);
    } else {
        println!("It's too big!!!");
        return 0;
    }
    */
}

3.2. 功能验证

下面验证结果仅使用常规方式实现的代码。
运行结果展示:

# 查看第 0 项
imaginemiracle:fibonacci$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.00s
     Running `target/debug/fibonacci`
The Fibonacci sequence demo: 0、1、1、2、3、5、8、13、21、34、...
Please enter the index of the fibonacci sequence:
0
The 0th Fibonacci number: 0
# 查看第 1 项
imaginemiracle:fibonacci$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.00s
     Running `target/debug/fibonacci`
The Fibonacci sequence demo: 0、1、1、2、3、5、8、13、21、34、...
Please enter the index of the fibonacci sequence:
1
The 1th Fibonacci number: 1
# 查看第 2 项
imaginemiracle:fibonacci$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.00s
     Running `target/debug/fibonacci`
The Fibonacci sequence demo: 0、1、1、2、3、5、8、13、21、34、...
Please enter the index of the fibonacci sequence:
2
The 2th Fibonacci number: 1
# 查看第 16 项
imaginemiracle:fibonacci$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.00s
     Running `target/debug/fibonacci`
The Fibonacci sequence demo: 0、1、1、2、3、5、8、13、21、34、...
Please enter the index of the fibonacci sequence:
16
The 16th Fibonacci number: 987

为了验证其计算功能,这里运行了多次。

再来看看它的错误输入检查功能如何:

imaginemiracle:fibonacci$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.00s
     Running `target/debug/fibonacci`
The Fibonacci sequence demo: 0、1、1、2、3、5、8、13、21、34、...
Please enter the index of the fibonacci sequence:
asljd
Please enter the correct index(like 1,2,3,...)!
-123
Please enter the correct index(like 1,2,3,...)!
qq
Please enter the correct index(like 1,2,3,...)!
🤗
Please enter the correct index(like 1,2,3,...)!
12
The 12th Fibonacci number: 144

笔者在这里还添加了上限检测函数,用于防止数值过大而导致的溢出错误。

imaginemiracle:fibonacci$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.01s
     Running `target/debug/fibonacci`
The Fibonacci sequence demo: 0、1、1、2、3、5、8、13、21、34、...
Please enter the index of the fibonacci sequence:
12312
It's too big!!!
The 12312th Fibonacci number: 0

目前姑且看起来是没问题的,那么这个题目暂时就这样了。

补充:
这里大家可能会问,为什么不验证递归实现的代码,是有问题吗?

回答:不是的,不,不完全是的。

按照代码的思路,是完全没有问题的,各位同学也可以使用上面递归的代码运行起来,输出小一点的索引(< 50)进行测试,结果一定是可以计算出来,且正确。为什么不建议输出大于 50 的值测试,原因就是,代码使用了递归,要知道,使用递归的好处是:代码简洁,实现简单; 同样的使用递归实现带来的弊端是:代码逻辑复杂,代码重入次数多,时间复杂度高。 通俗来讲就是 “递归实现是用复杂的处理逻辑和大量的代码重入,来换取简单的实现。可以用简单的几行代码实现复杂的功能。”

如果是按照上文中无溢出校验的递归实现的话,那么计算 index = n 结果, fibonacci() 函数的重入次数为 Fibonacci[n + 1]n > 2 时)。Fibonacci 数列为 0、1、1、2、3、5、8、13、21...,当 n > 2 时,用递归计算出第 n 个斐波那契数,则需要执行第 n + 1 个斐波那契数次的 fibonacci() 函数。

举个栗子🌰:
想要计算第 3 个斐波那契数,就需要执行 3fibonacci() 得出结果为 2
想要计算第 4 个斐波那契数,就需要执行 5fibonacci() 得出结果为 3
想要计算第 5 个斐波那契数,就需要执行 8fibonacci() 得出结果为 5
……
想要计算第 43 个斐波那契数,就需要执行 701408733fibonacci() 得出结果为 433494437
……
想要计算第 100 个斐波那契数,就需要执行 573147844013817200000fibonacci() 得出结果为 354224848179262000000
执行这么多次你的电脑得算很久很久(具体时间笔者没有统计),总之这种方法在数值较小的时候还是可以用用的,主要学习一下递归的思路。如果聪明的大家有更优秀的递归方法,欢迎在下面留言或直接私信笔者,非常愿意与大家一同讨论问题。

4. 所用到的知识点

在之前的文章中可能对几个函数用法以及原理没有解释清楚,这里重新整理一下。

4.1. str::trim()

str::trim() 该函数将会为调用它的字符串去除前后的空格或回车和换行,然后返回处理后的字符串。

返回值:去除前后空格或回车或换行后的字符串。

其函数原型为:

pub fn trim(&self) -> &str {
	self.trim_matches(|c: char| c.is_whitespace())
}

示例:

fn main() {

    let mut str = "   @@ImagineMiracle##   **  \n\n\n";

    println!("{}", str);

    str = str.trim();

    println!("{}", str);
}

运行结果:

imaginemiracle:trim$ cargo run
   Compiling trim v0.1.0 (/home/imaginemiracle/Miracle/Code/rust_projects/trim)
    Finished dev [unoptimized + debuginfo] target(s) in 0.23s
     Running `target/debug/trim`
   @@ImagineMiracle##   **



@@ImagineMiracle##   **

4.2. str::parse()

str::parse(),该函数将字符串解析为另一种类型。

返回值:Result 类型
因此需要对其返回的 Result 处理。

函数原型:

pub fn parse<F: FromStr>(&self) -> Result<F, F::Err> {
	FromStr::from_str(self)
}

示例:

fn main() {
    let str = "27149";

    // 使用 match 处理 Result
    let num: u32 = match str.parse::<u32>() {
        Ok(n1) => n1,
        Err(_) => {
            println!("Error.");

            0
        }
    };

    println!("str to num: {str} -> {num}");

    // 使用 expect 处理 Result
    let num: u32 = str.parse::<u32>().expect("Failed to u32");
    println!("str to num: {str} -> {num}");

    // 使用 unwrap 处理 Result,出错后将会程序将会报 panic 错误同时崩溃并退出
    let num: u32 = str.parse().unwrap();
    println!("str to num: {str} -> {num}");
}

运行程序:

imaginemiracle:parse$ cargo run
   Compiling parse v0.1.0 (/home/imaginemiracle/Miracle/Code/rust_projects/parse)
    Finished dev [unoptimized + debuginfo] target(s) in 0.55s
     Running `target/debug/parse`
str to num: 27149 -> 27149
str to num: 27149 -> 27149
str to num: 27149 -> 27149

4.3. match 表达式

match 表达式可用于匹配 arm 中的各个条件,而选择性的执行其中一个符合条件的 arm

示例01:

fn main() {

    let num = 3;

    match num {
        0 => println!("zero"),
        1 => println!("one"),
        2 => println!("two"),
        3 => println!("three"),
        _ => println!("something else"),
    }
}

运行结果:

imaginemiracle:match_test$ cargo run
   Compiling match_test v0.1.0 (/home/imaginemiracle/Miracle/Code/rust_projects/match_test)
    Finished dev [unoptimized + debuginfo] target(s) in 1.02s
     Running `target/debug/match_test`
three

示例02:
可以使用简单的条件作为判断。

fn main() {

    let nums = [1, 2, 3, 6];

    for num_i in nums {
        let message = match num_i {
            0 | 1 => "0 or 1",
            2 ..= 3 => "[2, 3]",
            4.. => "[4, ...)",
            _ => "something else"
        };

        println!("{}", message);
    }
}

其中 ..=.. 表示范围,2 ..= 3 表示 2 <= x <= 34.. 表示 x >= 4
运行结果:

imaginemiracle:match_test$ cargo run
   Compiling match_test v0.1.0 (/home/imaginemiracle/Miracle/Code/rust_projects/match_test)
    Finished dev [unoptimized + debuginfo] target(s) in 0.38s
     Running `target/debug/match_test`
0 or 1
[2, 3]
[2, 3]
[4, ...)

示例03:
也可在其中使用 if 表达式做条件判断。

fn main() {

    let str1 = "Imagine";
    let str2 = "Miracle";

    match str1 {
        str if (str == "Imagine") => println!("Imagine"),
        str if (str == "Miracle") => println!("Miracle"),
        _ => println!("Others")
    }


    match str2 {
        str if (str == "Imagine") => println!("Imagine"),
        str if (str == "Miracle") => println!("Miracle"),
        _ => println!("Others")
    }

}

运行结果:

imaginemiracle:match_test$ cargo run
   Compiling match_test v0.1.0 (/home/imaginemiracle/Miracle/Code/rust_projects/match_test)
    Finished dev [unoptimized + debuginfo] target(s) in 0.23s
     Running `target/debug/match_test`
Imagine
Miracle

Boys and Girls!!!
准备好了吗?下一节我们要还有一个小练习要做哦!

不!我还没准备好,让我先回顾一下之前的。
上一篇《Rust 中的条件、循环结构——Rust语言基础08》

我准备好了,掛かって来い(放马过来)!
下一篇《Rust 实现摄氏度与华氏度相互转换——Rust语言基础10》


觉得这篇文章对你有帮助的话,就留下一个赞吧v*
请尊重作者,转载还请注明出处!感谢配合~
[作者]: Imagine Miracle
[版权]: 本作品采用知识共享署名-非商业性-相同方式共享 4.0 国际许可协议进行许可。
[本文链接]: https://blog.csdn.net/qq_36393978/article/details/125741139

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Imagine Miracle

爱你哟 =^ v ^=

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值