斐波那契 递归与非递归
关键字: 斐波那契
1递归
<code>
int fib(int n)
{if(n==1||n==2) return 1;
else return fib(n-1)+fib(n-2);
}
</code>
2非递归
<code>
public class Fibonacci {
public static int fibo2(int n) {
if(n==0 || n==1) {
return n;
}
int f0=1, f1=1, f2=2;
for(int i=2; i<=n; ++i) {
f2 = f0 + f1;
f0 = f1;
f1 = f2;
}
return f2;
}
}
<<编程珠玑>>看到一篇关于二分查找算法的分析, 觉得说得特别好,以前数据结构也学过这个算法,下面就把书上的大致意思加上自己的一些研究和看法做个总结.
二分查找的算法可以分为递归与非递归算法.下面的这两种算法的实现形式
递归算法
int BinarySearch(int l, int u)
{
int m = 0;
if(l > u)
return -1;
//m = (l + u) / 2;
// m = l + ((u-l)/2);
m = l + ((u-l)>>1); // this is a change
if(key == array[m])
return m;
else if(key < array[m])
{
u = m - 1;
BinarySearch(l, u);
}
else if(key > array[m])
{
l = m + 1;
BinarySearch(l, u);
}
}
非递归算法
int BinarySearch(int l, int u)
{
int m = 0;
while(l <= u)
{
m = (l + u) / 2;
if(key == array[m])
return m;
else if(key < array[m])
u = m - 1;
else
l = m + 1;
}
return (-1);
}
递归的算法比较容易理解,但执行速度稍慢,我在vc环境下profile过,性能确实比非递归稍差.
<<编程珠玑>>上说90%的程序员写不出无bug的二分查找程序,作者主要基于测试用例来讲的,意思是说测试的情况有很多,要考虑到很多情况. 作者是专门研究算法的,研究问题在我看来是有点”钻牛角尖”, 但是如果应用到实际开发中,我们应该由此想到的是代码的健壮性. 由其是嵌入式领域, 一个数据溢出错误就可能导致一台医疗仪器害死一个病人,或者航天飞机上不了天.
说到代码的健壮性,拿上面的二分查找为例,
m = (l+u)/2
这一行代码就有问题, 如果l+u溢出怎么办(l, u两个数假定都不会溢出) ? 网上看到有人说把l和u声明为无符号数,这显然不行, 因为无符号数也会溢出, 尽管溢出的标志位与有符号位不同. 不管溢出的结果是不是不可预知的,对于二分查找,有无符号数计论下去都是没意义的. 也看到另外一种方法就是
m = l + ((u-l)/2).
这的确是一个不错的方法. 在l和u保证不溢出的情况下, m肯定不会溢出的. 另外如果把(u-l)/2 改成(u-l)>>1 就更好了, 因为了u-l肯定是大于等于零的, 右移和除法的效果是一样的(如果是负数的话,除法和右移有一点区别,这里不说明).
还有一种方法就是如果用了计算机所能支持的最大的数据长度还是会有溢出的可能,就干脆加assert, 因为一个明确的错误的提示也是代码健壮性的体现.