我对递归的初步了解

论道无法目前无法用markdown语法
http://note.youdao.com/noteshare?id=7a2cfa7d7397bbd77cb6a511dcb61ce6 
可以直接访问链接
# 递归
## 简单递归
```
    function factorial(n){
        if(n == 1 ){return 1}
        
        return n*factorial(n-1)
    }
    
    
    function fib(n){
        if( n == 0 ){return 0}
        if( n == 1 || n ==2){return 1}
        
        return fib(n-1) + fib(n-2)
    }
```
以上是简单的一看大概就数学类递归,
递归有很明显的两个组成部分
先看出来的结果,结果必然是同名函数或方程(没有最终输出之前),
然后必须要有输出的结果(一定要有递归结束条件)

## 递归应用
假定有1美分,5美分,10美分,25美分,50美分的零钱无限多,试把任意钱换成零钱,写一个函数计算有多少种换法。

请将代码写在count_change函数里,返回有多少种换算方法。该函数有一个参数,传入的是一个数字,单位是美分,比如,1美元,传入的是100美分。
```
function count_change(amount, valueIndex=5){
    //首先程序不是人,要一步一步进行运算
    
    if(amount < 0 || valueIndex <= 0 ){return 0}
    //结束条件一,钱数到负数,或者已经没有下一个值给我用了,说明此路不通
    if(amount === 0){return 1}
    //结束条件而,钱刚刚好数完,说明这是一种方法 输出1

    //如果上面两种条件没有达到,说明程序要进行下一步, 
    //分解成两个结果的组合
    //一个是减去最大的数值后,还剩下几种
    //一个是下一个币值有几种
    return count_change_rest_value(amount,valueIndex) + count_change_next_value(amount,valueIndex)
}
function count_change_rest_value(amount,valueIndex){
    var val = valueSpace[valueIndex]
    var rest = amount - val
    //上面求得了剩下的数值,然后重新放到能实现结果的方程
    return count_change(rest , valueIndex)
}
function count_change_next_value(amount,valueIndex){
    //直接进入到下一个币值的计算
    return count_change(amount,valueIndex-1)
}
//用对象实现逻辑的对应
var valueSpace = {
    5:50,
    4:25,
    3:10,
    2:5,
    1:1,
}

    
```
### 思考题
写一个f函数,满足下面的需求:

如果 n < 3,那么f(n) = n
如果 n >= 3, 那么 f(n) = f(n-1)+2f(n-2)+3f(n-3)
伪代码
f(n){
    如果小于n 输出 n
    如果大于n 输出 怎么样输出同名函数
}
## 难度加大的递归
实现pascal_triangle函数,以打印帕斯卡三角(即杨辉三角)
> 1  
> 1 1  
> 1 2 1  
> 1 3 3 1  
> 1 4 6 4 1  

这个问题,如果用迭代写非常简单,无非是根据上一个数组生成当前数组,但是如果是用递归,最难的地方是如何复用当前的函数/方程
我之前用了狗屁膏药的方式实现过一个,但是为了颜面,在这里用点脑子,就是把三角补充成矩阵

```
function pascal_triangle(n, prvRect=[1]){
    //如果一开始的话 是没有输入数组,所以用了默认值   
    if(prvRect.length == n){return prvRect}
    //结果仅仅当发现矩阵 大小是目标长度才输出
    
    nextRect = getPrvRectFillZero(prvRect)
    //递归过程中 给出了上一个矩阵,补充零
    nextRect.push(getNextArr(prvRect))
    //上一个矩阵,再加上新的数组就是我想要的杨辉三角
    return pascal_triangle(n,nextRect)
}
function getPrvRectFillZero(prvRect){
    if(prvRect.length == 1){ return [[1,0]] }
    //由于下面用到循环,所以如果prvRect的长度不大于1就出bug,特殊值用子程序剔除
    for(var i = 0; i < prvRect.length-1; i++) {
        prvRect.push(0)
    }
    return prvRect
}
function getNextArr(prvRect){
    if(prvRect.length == 1){ return[1,1]}
     //由于下面用到循环,所以如果prvRect的长度不大于1就出bug,特殊值用子程序剔除
    var nextArr =
    var prvArr = prvRect[prvRect.length-1]
    prvArr.push(0)
    for(var i = 0; i < prvArr.length; i++) {
        var num = getTwo(i,prvArr)
        //这里的数值是根据一个数组生成,就这样放着,等会实现
        nextArr.push(num)
    }
    return nextArr
}
function getTwo(i,arr){
    if(arr.length == 1 || i==0 ){return 1}
     //由于下面用到循环,所以如果prvRect的长度不大于1就出bug,特殊值用子程序剔除
    return arr[i-1] + arr
[i]    //如果把需求脱离出来,就发现每一步都很简单
}

```
### 思考题
实现gcd函数,用欧几里得法求两个参数的最大公约数 这一算法基于下面的观察,如果r是a和b的余数,那么a和b的公约数正好也是b和r的公约数,因此我们可以借助等式

gcd(a,b) = gcd(b,r)
伪代码
gcd(a,b){   
    当 b 等于零 输出   
    求出a b的余数 a%b
    输出 怎么样的gcd 接受什么样的参数
}
[/i]

0 个评论

要评论文章请先登录注册