循环

不断重复进行某一运算、操作

迭代

不断对前一旧值运算得到新值,直到达到精度。一般用于得到近似目标值,反复循环同一运算(函数),并且总是把前一次运算结果反代回运算式进行下一次运算

递推

从初值出发反复进行某一运算得到所需结果。从已知到未知,从小到大

回溯

回溯是一种算法思想,可以用递归实现。通俗点讲回溯就是一种试探,类似于穷举,但回溯有“剪枝”功能,比如求和问题。给定7个数字,1 2 3 4 5 6 7求和等于7的组合,从小到大搜索,选择1+2+3+4 =10>7,已经超过了7,之后的5 6 7就没必要在继续了,这就是一种搜索过程的优化。如果还有不清楚的可以看一下8皇后问题。

递归

从所需结果出发不断回溯前一运算直到回到初值再递推得到所需结果。从未知到已知,从大到小,再从小到大。递归是从归纳法衍生出来的。
一个运算(操作),可以通过不断调用本身的运算形式,往往需要通过前一次的结果来得到当前运算的结果,因而,程序运行时,总是先一次次地【回溯】前一次的结果(回溯过程中这些结果是未知的,直到回溯到初值令回溯终止,再层层递推回来得到当前要求的值)
一个完整的递归应该有下面三个条件,否则就是不合格的递归

  1. 明确递归的终止方法(一个递归必须有他递推到头的界定,否则将会是无限递归)

  2. 明确的终止时处理方法

  3. 重复调用自身并缩小问题规模

在有循环的语言里,有的人认为尾递归优化出了炫技之外是完全无用的。其实不然,尾递归写法有一下好处

  1. 强迫你把循环写成单独的函数。这又有什么好处呢?这会影响你的编程风格,习惯使用尾递归之后,你的写出一个几百行大函数的机率会小得多。

  2. 保证没有副作用,统一使用不可变数据。在循环里,循环变量就是一个可变数据。作为人肉开发者,如果想保证自己的某段程序没有副作用,最好的做法就是根本不要写任何带副作用的东西,这样代码审查时一眼看过去就能知道有没有副作用。至于避免副作用有什么好处,这又可以写一篇文章,这里就不展开了。

  3. 转换成惰性序列时比较好看。在某些语言里,尾递归形式基本上只要去掉循环变量(变成无限递归), 把初始状态作为首元素,就是一个能直接拿来用的惰性序列。

“递归”是一种思路,这种思路的特点是:我不关注问题本身,我只关注这个问题如何可以用一种可重复的方式分解为一些规模更小的子问题,以及这些子问题与原问题的关系。再加上当问题的规模足够小的时候,存在一个简单直接的解法。

//递归求解
function fib($n){
    return $n <2?1:fib($n-1) + fib($n-2);
}
//递推求解
function fib($n){
    $start=0;
    $fn=1;
    for ($i=0;$i<$n;$i++) {
        $t=$fn;
        $fn=$fn+$start;
        $start=$t;
    }
    return $fn;
}

尾调用优化

Scroll to Top