zoukankan      html  css  js  c++  java
  • 递归

    ## 什么是递归

    在程序中, 所谓的递归, 就是函数自己直接或间接的调用自己.

    1. 直接调用自己
    2. 间接调用自己

    就递归而言最重要的就是跳出结构. 因为跳出了才可以有结果.

    ## 所谓的递归就是化归思想

    递归的调用, 写递归函数, 最终还是要转换为自己这个函数.

    假如有一个函数 f, 如果它是递归函数的话, 那么也就是说 函数体内的问题还是转换为 f 的形式.

    递归思想就是将一个问题转换为一个已解决的问题来实现

    ```
    function f() {
    ... f( ... ) ...
    }
    ```


    例子: 1, 2, 3, 4, 5, ..., 100

    1. 首先假定递归函数已经写好, 假设是 foo. 即 foo( 100 ) 就是求 1 到 100 的和
    2. 寻找递推关系. 就是 n 与 n-1, 或 n-2 之间的关系: foo( n ) == n + foo( n - 1 )
    ```
    var res = foo( 100 );
    var res = foo( 99 ) + 100;
    ```
    3. 将递推结构转换为 递归体
    ```
    function foo( n ) {
    return n + foo( n - 1 );
    }
    ```
    * 将 求 100 转换为 求 99
    * 将 求 99 转换为 求 98
    * ...
    * 将求 2 转换为 求 1
    * 求 1 结果就是 1
    * 即: foo( 1 ) 是 1
    4. 将临界条件加到递归体中
    ```
    function foo( n ) {
    if ( n == 1 ) return 1;
    return n + foo( n - 1 );
    }
    ```


    练习: 求 1, 3, 5, 7, 9, ... 第 n 项的结果与前 n 项和. 序号从 0 开始

    **求第 n 项的**
    1. 首先假定递归函数已经写好, 假设是 fn. 那么 第 n 项就是 fn( n )
    2. 找递推关系: fn( n ) == f( n - 1 ) + 2
    3. 递归体
    ```
    function fn( n ) {
    return fn( n-1 ) + 2;
    }
    ```
    4. 找临界条件
    * 求 n -> n-1
    * 求 n-1 -> n-2
    * ...
    * 求 1 -> 0
    * 求 第 0 项, 就是 1
    5. 加入临界条件
    ```
    function fn( n ) {
    if ( n == 0 ) return 1;
    return fn( n-1 ) + 2;
    }
    ```

    **前n项和**
    1. 假设已完成, sum( n ) 就是前 n 项和
    2. 找递推关系: 前 n 项和 等于 第 n 项 + 前 n-1 项的和
    3. 得到递归体
    ```
    function sum( n ) {
    return fn( n ) + sum( n - 1 );
    }
    ```
    4. 找临界条件
    * n == 1 结果为 1
    5. 得到递归函数
    ```
    function sum( n ) {
    if ( n == 0 ) return 1;
    return fn( n ) + sum( n - 1 );
    }
    ```

    练习: 2, 4, 6, 8, 10 第 n 项与 前 n 项和

    **第n项**
    ```
    function fn( n ) {
    if ( n == 0 ) return 2;
    return fn( n-1 ) + 2;
    }
    ```
    **前n项和**
    ```
    function sum( n ) {
    if ( n == 0 ) return 2;
    return sum( n - 1 ) + fn( n );
    }
    ```

    练习: 数列: 1, 1, 2, 4, 7, 11, 16, … 求 第 n 项, 求前 n 项和.

    **求第 n 项**
    1. 假设已经得到结果 fn, fn( 10 ) 就是第 10 项
    2. 找递推关系
    * 0, 1 => fn( 0 ) + 0 = fn( 1 )
    * 1, 2 => fn( 1 ) + 1 = fn( 2 )
    * 2, 3 => fn( 2 ) + 2 = fn( 3 )
    * ...
    * n-1, n => fn( n-1 ) + n - 1 = fn( n )
    3. 递归体也就清楚了, 临界条件是 n == 0 => 1
    ```
    function fn( n ) {
    if ( n == 0 ) return 1;
    return fn( n-1 ) + n - 1;
    }
    ```

    **如果从 1 开始表示, 那么第 n 项为**
    1. 假设已经得到结果 fn, fn( 10 ) 就是第 10 项
    2. 找递推关系
    * 1, 2 => fn( 1 ) + 0 = fn( 2 )
    * 2, 3 => fn( 2 ) + 1 = fn( 3 )
    * 3, 4 => fn( 3 ) + 2 = fn( 4 )
    * ...
    * n-1, n => fn( n-1 ) + n - 2 = fn( n )
    3. 临界条件 n == 1 => 1


    **前n项和**
    ```
    function sum( n ) {
    if ( n == 0 ) return 1;
    return sum( n - 1 ) + fn( n );
    }
    ```


    如果从 0 开始
    ```
    0 1 2 3 4 5 6
    1, 1, 2, 4, 7, 11, 16,
    ```
    如果从 1 开始
    ```
    1 2 3 4 5 6 7
    1, 1, 2, 4, 7, 11, 16,
    ```


    练习: Fibonacci 数列: 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, …

    求其第 n 项.

    递推关系 fn(n) == fn( n- 1) + fn( n - 2)

    ```
    function fib( n ) {
    if ( n == 0 || n == 1 ) return 1;
    return fib( n - 1 ) + fib( n - 2 );
    }
    ```

    ## 阶乘

    阶乘是一个运算, 一个数字的阶乘表示的是从 1 开始 累乘到这个数字. 例如 3! 表示 `1 * 2 * 3`.
    5! 就是 `1 * 2 * 3 * 4 * 5`. 规定 0 没有阶乘, 阶乘 从 1 开始.

    求 n 的阶乘
    ```
    function foo ( n ) {
    if ( n == 1 ) return 1;
    return foo( n - 1 ) * n;
    }
    ```

    ## 求幂

    求幂就是求 某一个数 几次方

    2*2 2 的 平方, 2 的 2 次方

    求 n 的 m 次方

    最终要得到一个函数 power( n, m )

    n 的 m 次方就是 m 个 n 相乘 即 n 乘以 (m-1) 个 n 相乘

    ```
    function power ( n, m ) {
    if ( m == 1 ) return n;
    return power( n, m - 1 ) * n;
    }
    ``

    # 深拷贝

    如果要实现深拷贝那么就需要考虑将对象的属性, 与属性的属性, ... 都拷贝过来

    如果要实现:
    1. 假设已经实现 clone( o1, o2 ), 将对象 o2 的成员拷贝一份交给 o1
    2. 简单的算法, 将 o2 的属性拷贝到 o1 中去
    ```
    function clone( o1, o2 ) {
    for ( var k in o2 ) {
    o1[ k ] = o2[ k ];
    }
    }
    ```
    3. 找递推关系, 或叫划归为已经解决的问题
    * 假设方法已经实现, 问一下, 如果 o2[ k ] 是对象
    * 继续使用这个方法
    * 因此需要考虑的是 o2[ k ] 如果是引用类型, 再使用一次 clone() 函数
    * 如果 o2[ k ]不是引用类型, 那么 就直接赋值
    ```
    function clone( o1, o2 ) {
    for ( var k in o2 ) {
    if ( typeof o2[ k ] == 'object' ) {
    o1[ k ] = {};
    clone( o1[ k ] , o2[ k ] );
    } else {
    o1[ k ] = o2[ k ];
    }
    }
    }
    ```


    复杂实现: clone( o ) -> newObj

    ```
    function clone( o ) {
    var temp = {};
    for ( var k in o ) {
    if ( typeof o[ k ] == 'object' ) {
    temp[ k ] = clone( o[ k ] );
    } else {
    temp[ k ] = o[ k ];
    }
    }
    return temp;
    }
    ```

    ## 请用 递归实现 getElementsByClassName
    ```
    <div>
    <div>1
    <div class="c">2</div>
    <div>3</div>
    </div>
    <div class="c">4</div>
    <div>5
    <div>6</div>
    <div class="c">7</div>
    </div>
    <div>8</div>
    </div>
    ```

    1. 如果实现一个方法 byClass( node, 'c', list ), 表示在某一个节点上查找符合 class 属性为 c 的元素
    2. 在当前元素的子元素中查找, 如果有符合要求的, 存储到一个数组中
    3. 首先遍历 子节点, 然后看子节点是否还有子节点, 如果没有直接判断, 如果有再递归

    ```
    function byClass( node, className, list ) {
    var arr = node.childNodes;

    for ( var i = 0; i < arr.length; i++ ) {
    if ( arr[ i ].className == className ) {
    list.push( arr[ i ] );
    }

    if ( arr[ i ].childNodes.length > 0 ) {
    byClass( arr[ i ], className, list );
    }
    }
    }
    ```

  • 相关阅读:
    android中数据存储
    服装销售系统数据库课程设计(MVC)
    重新设计的道道指令
    CSS cursor属性
    hdu4488 Faulhaber’s Triangle(模拟题)
    SPOJ 1043 1043. Can you answer these queries I
    再谈内存管理与ARC运行机制(一)
    PowerMock注解PowerMockIgnore的使用方法
    hdu 1317 XYZZY【Bellheman_ford 判断正环小应用】
    HDU 1104 Remainder( BFS(广度优先搜索))
  • 原文地址:https://www.cnblogs.com/huqinhan/p/5745243.html
Copyright © 2011-2022 走看看