算法与数据结构(邓俊辉)第一章
斐波那契数列
斐波那契数列几种方法快慢的对比
//头文件
#pragma once
class Fib { //Fibonacci数列类
private:
int f, g; //f = fib(k - 1), g = fib(k)。均为int型,很快就会数值溢出
public:
Fib(int n) //初始化为不小于n的最小Fibonacci项
{
f = 1; g = 0; while (g < n) next();
} //fib(-1), fib(0),O(log_phi(n))时间
int get() { return g; } //获取当前Fibonacci项,O(1)时间
int next() {
g += f;
f = g - f;
return g;
} //转至下一Fibonacci项,O(1)时间
int prev() {
f = g - f;
g -= f;
return g;
} //转至上一Fibonacci项,O(1)时间
};
/******************************************************************************************
* Data Structures in C++
* ISBN: 7-302-33064-6 & 7-302-33065-3 & 7-302-29652-2 & 7-302-26883-3
* Junhui DENG, deng@tsinghua.edu.cn
* Computer Science & Technology, Tsinghua University
* Copyright (c) 2003-2020. All rights reserved.
******************************************************************************************/
#include<ctime>
#include<iostream>
#include<stdio.h>
using namespace std;
#include "Fib.h"
__int64 fibI(int n); //迭代版
__int64 fib(int n); //二分递归版
__int64 fib(int n, __int64& f); //线性递归版
int main(int argc, char* argv[]) { //第一次写这种主函数带参数的程序,调试的方法有以下几种:
//方法一: 调试后,找到exe文件所在的位置Debug里,具体位置因人而异。
//参考http://blog.csdn.net/lyj_viviani/article/details/51817755这里的命令行使用方法,
//在exe文件夹中shift+右击,选择“在此处打开命令窗口”,按TAB键切换文件,选择exe文件,输入参数回车
//方法二:
//进入项目【项目】—>【属性】—>【调试】—>【命令参数】—>输入a b c d,如果有多个字符串参数,则用空格隔开。比如要读入两张图片,在命令参数里输入
//检查参数
if (2 > argc) {
fprintf(stderr, "Usage: %s <rank>\n", argv[0]);
return 1;
}
int n = atoi(argv[1]);
// 依次计算Fibonacci数列各项
printf("\n------------- class Fib -------------\n");
Fib f(0);
for (int i = 0; i < n; i++, f.next())
printf("fib(%2d) = %d\n", i, f.get());
for (int i = 0; i <= n; i++, f.prev())
printf("fib(%2d) = %d\n", n - i, f.get());
printf("\n------------- Iteration -------------\n");
for (int i = 0; i < n; i++)
printf("fib(%2d) = %22I64d\n", i, fibI(i));
printf("\n------------- Linear Recursion -------------\n");
for (int i = 0; i < n; i++) {
__int64 f;
printf("fib(%2d) = %22I64d\n", i, fib(i, f));
}
printf("\n------------- Binary Recursion -------------\n");
for (int i = 0; i < n; i++)
printf("fib(%2d) = %22I64d\n", i, fib(i));
return 0;
}
//动态规划,颠倒计算方向:自顶而下递归,为自底而上迭代。爬楼梯可以用这种方法
__int64 fibI(int n) { //计算Fibonacci数列的第n项(迭代版):O(n)
__int64 f = 1, g = 0; //初始化:fib(-1)、fib(0)
while (0 < n--) { //这种方法比较难理解
g += f;
f = g - f;
} //依据原始定义,通过n次加法和减法计算fib(n)
return g; //返回
}
__int64 fib(int n) { //计算Fibonacci数列的第n项(二分递归版):O(2^n)
return (2 > n) ?
(__int64)n //若到达递归基,直接取值
: fib(n - 1) + fib(n - 2); //否则,递归计算前两项,其和即为正解
}
//回归迭代,将已计算过的实例的结果制表备查
__int64 fib(int n, __int64& prev) { //计算Fibonacci数列第n项(线性递归版):入口形式fib(n, prev)
if (0 == n) //若到达递归基,则
{
prev = 1; return 0;
} //直接取值:fib(-1) = 1, fib(0) = 0
else { //否则
__int64 prevPrev;
prev = fib(n - 1, prevPrev); //递归计算前两项
return prevPrev + prev; //其和即为正解
}
} //用辅助变量记录前一项,返回数列的当前项,O(n);