闲耘.博客

巨人归来。

今天看了dennis的《用递归计算阶乘咋不行呢?》受益良多,这里做下小结。

传统的递归算法写起来很漂亮,代码很简洁,但是没递归一次就需要更深一层的堆栈支持,可能会造成内存溢出而失败,所以递归和goto语句一样声名狼藉。

甚至《代码大全》的作者有这样一句话:如果为我工作的程序员用递归去计算阶乘,那么我宁愿换人。作者对递归的态度相当谨慎,这在静态命令式语言中显然是正确的,但是在函数式语言中,由于有尾递归优化的存在,递归反而是最自然的形式,况且我打心里认为递归更符合人类思维。(by dennis)


尾递归就是从最后开始计算,每递归一次就算出相应的结果,也就是说,函数调用出现在调用者函数的尾部,因为是尾部,所以根本没有必要去保存任何局部变量,直接让被调用的函数返回时越过调用者,返回到调用者的调用者去。举例说明。
线性递归(传统递归方式):

function recursion(n){
    return n==1?1:n*recursion(n-1);
}

尾递归:

function tailRecursion(n, a){
    a = a||1; // 尾递归之尾,即上次递归结果。
    return n==1?a:tailRecursion(n-1, a*n);
}



这里将基于尾递归的求数值阶乘算法贴下:

Math.factorial_III = function(n){
    var a = arguments[1]||1;
    return n<=1?a:Math.factorial_III(n-1, a*n);
};

效率上和循环迭代、阶乘改进算法相当甚至稍胜出(ie6,firefox2,safari3),普通递归的效率最为底下,且需要深入堆栈。

参考:
尾递归》-百度百科
用递归计算阶乘咋不行呢?》-dennis

以前用过各种博客系统,自己也写了一个(由于朋友赞助的服务器无法继续使用,只留了在本地演示)。很长时间以来一直使用Google收购的Blogger.com提供的服务,并绑定到自己的blog.xianyun.org域名下,由于国内过于和谐的缘故,Google DNS服务器也无法访问了,就另图出路。久仰WordPress大名,特来瞻仰。

 大概是系统的原因,以前在Blogger.com的日志暂时无法导入过来,实在是遗憾。

昨天申请的帐号,今天写第一篇,以自贺乔迁之喜。最近对数学再返无穷兴趣,在一个数学方面极好的博客上读得关于阶乘计算的好文,就把其中一个较易实现的改进算法发布如下(Javascript实现),初来乍到,不知道怎么发布源代码,请见谅:

/**
 * 求阶乘的改进算法。
 * @param {Number, Integer} n 求阶乘的目标整数。
 * @see <a href="http://www.matrix67.com/blog/article.asp?id=442“>计算阶乘的另一些有趣的算法</a>,
 *  <a href=”http://www.luschny.de/math/factorial/index.html“>巨牛,20多种阶乘算法的代码</a>
 */
Math.factorial_II = function(n){
    if (n.isNegativeInteger()){throw new Error(”param error.”)}
    if (n===0){return 1;}
    var m=(n.isOdd()?(n+1):n)/2; // middle number.
    var r = n.isOdd()?m:m*n; //result;
    for (var i=1; i<m; i++){
        r*=(Math.pow(m,2) - Math.pow(i,2));
    }
    return r;
};

/**
 * 判断当前数值对象是否是整数。
 * @return {Boolean} true,如果数值是整数,否则返回false。
 */
Number.prototype.isInteger = function(){
    return /^[+-]?d+$/.test(this);
};

/**
 * 判断数值是否是为负数。
 * @return {Boolean} true,如果数值是负数,否则返回false。
 */
Number.prototype.isNegative = function(){
    return this<0;
};

/**
 * 判断数值是否为负整数。
 * @return {Boolean} true,如果数值为负整数,否则返回false。
 */
Number.prototype.isNegativeInteger = function(){
    return this.isNegative() && this.isInteger();
};

/**
 * 判断当前数字的值是否为奇数(定义:不能被2整除的(整)数,如1,3和5)。
 * 关于零(0)是否属于偶数,目前似乎尚无定论,这里不予理会,作为偶数处理。
 * @return {Boolean} true,如果当前值是奇数,否则,返回false。
 */
Number.prototype.isOdd = function(){
    /* Javascript整除(取模)运算:
     * 被除数为正整数时,结果为0或1;
     *       为负整数时,结果为0或-1;
     *       为0时,结果为0;
     *       为小数时,结果为正或负小数。
     */
    return this.isInteger() && ((this%2)!==0);
};

三个学生在旅社住宿,房费是30元。三人每人给了10元住在一间房。恰遇那天打折只要25元,老板拿出了5元,让服务员还给学生。服务员偷偷藏了2元,给了每人一元。
这样,每人都只用了9元,3乘以9加上服务员藏起来的2元一共是29元,还有一元钱呢?


是啊,还有一块呢,根据守衡定律,这一块总不能凭空就没啦,太不划算了。
一块钱能买多少东西啊,说都说不完 (说怎么会说得完呢,花才会花得完的 ^_-)。

言归正传,这一块到底哪去得?大家都是明眼人,它自己是不会跑得掉的。
原来作者只在一个小地方做了手脚,借此来糊弄人。

“每人都只用了9元,3乘以9加上服务员藏起来的2元一共是29元”。
这里应该做加法运算吗?您认为呢。

闲耘愚笨,确是被作者糊弄了一次。不过一块钱可不是一笔小数目,总算被我讨回来了。   :)


另:因为群中有人提出这个问题,几个也许被暂时”糊弄”的人吵嘴起来,闲耘多嘴,也管不住自己,笑云:
 
看来这不能叫”QQ群”
应该叫”QQ堆”
一堆不能和睦相处的人