小菲波那契数的计算程序
刚开始写程序的人往往不愿意对问题进行细致的分析,他们喜欢多用一些空间来表示问题的结构,从而简化程序的控制部分。为计算菲波那契数,定义一个数组f,f[i]用于存放第i项菲波那契数。一个初学者的程序看起来可能是下面的样子:
// Program: Fib_0
#define MAX_SIZE
20
int Fib(int n)
{
int f[MAX_SIZE+1];
int i;
f[0] = f[1] = 1;
for (i = 2; i <= n; i++)
f[i] = f[i - 1] + f[i - 2];
return f[n];
}
在核心循环中,f[i]的计算仅需用到f[i-1]和f[i-2],如果用两个变量f0、f1分别表示f[i-1]和f[i-2],通过增加一点点控制就可以省去数组f,相应的程序为:
// Program: Fib_1
// 定义宏SWAP,交换两个变量的值
#define SWAP(x, y)
(x^=y^=x^=y)
int Fib(int n)
{
int f0, f1;
int i;
if (n == 0 || n == 1) return 1;
f0 = f1 = 1;
// 在进入循环时,f0=f[i-2],f1=f[i-1],出循环时f0=f[i-1],f1=f[i]
for (i = 2; i <= n; i++)
{
f0 += f1;
SWAP(f0, f1);
}
return f1;
}
SWAP通过计算完成两个变量值的交换目的,其依据为:
x^(x^y)=y
y^(x^y)=x
“^”表示异或操作。核心循环可以有多种写法,例如:可引入一个中间变量来完成f0、f1的交换任务:
// Program: Fib_2
int Fib(int n)
{
int f0 = 1, f1 = 0, f;
int i;
for (i = 0; i <= n; i++)
{
f = f0 + f1;
f0 = f1;
f1 = f;
}
return f;
}
或者利用菲波那契数的性质得到
// Program: Fib_3
int Fib(int n)
{
int f0 = 1, f1 = 0;
int i;
for (i = 0; i <= n; i++)
{
f1 += f0;
f0 = f1 - f0;
}
return f1;
}
也可以不引入任何中间变量,而是在进入循环时,判断i是否偶数,若2|i,则保证f0=f[i-2],f1=f[i-1],否则,f0=f[i-1],f1=f[i-2]。相应的程序为:
// Program: Fib_4
int Fib(int n)
{
int f0 = 0; f1 = 1;
int flag = 0;
int i;
for (i = 0; i <= n; i++)
{
if (flag == 0)
f0 = f0 + f1;
else
f1 = f0 + f1;
flag = 1 - flag;
}
if (flag == 0) return f0;
return f1;
}
在上面的五种计算程序中,考虑到程序逻辑的清晰性和可理解性,程序Fib_2是最可取的。