/** * 递归 */ 递归:在函数定义中调用自身 // 1, C 中不是所有数学递归运算都是高效的;递归应尽量简短 2, 使用递归进行数学运算是一个坏主意 3, 取余运算很昂贵,因为 N % 10 = N - N / 10 * 10 4, 不要用递归代替循环;也就是说不用用递归作循环该做的事 5, 递归原则; i. 递归过程中必须有结束递归的情况(base case),也就是不需要递归直接可以得到结果的情况,防止递归无限进行 ii. 递归过程应该总是趋向于结束情况(base case) iii. 假设所有递归调用都是正确的,没必要去考虑递归的每次调用过程是怎样的 iv. 递归过程中不要有 对同一种情况递归计算多次 6, 尾递归(Tail Recursion) 尾递归是指在函数的最后一行调用本身的递归。在最后一行进行递归调用。 尽量避免尾递归,因为相对来说,尾递归需要保存太多的东西(如变量,调用地址) 7, 举例:C 描述 int badExample_1( unsigned int N) { if( N == 0){ return 0; }else{ return badExample_1( N/3 + 1) + N - 1; } } //说明:违反了 rule ii. badExample_1( 1) 会调用 badExample_1( 1),因此无法得到结果,递归会无限的进行。 badExample_1( 2) 也会调用 badExample_1( 1), 因此这个递归无意义;只有 N = 0 时能得到结果 // long int badExample_2(unsigned int N) { if( N == 1){ return 1; }else{ return N * badExample_2( N -1); } } //说明:使用 递归作了 循环该做得事 是程序的时间复杂度难以计算 // long int fibonacci( int N) { if( N == 0){ return 0; }else if( N == 1){ return 1; }else{ return fibonacci( N - 1) + fibonacci( N - 2); } } //说明:违反了 rule iv. 递归过程中对同一情况多次计算 fibonacci( 4) 会调用 fibonacci( 3) 和 fibobacci( 2);而 fibonacci( 3) 又会调用 fibonacci( 2) 和 fibonacci( 1), 因此 fibonacci( 4) 的递归过程中就计算了两次 fibonacci(2) // JavaScript 利用 closure 计算 fibonacci 序列 var fibonacci = function(){ var fib_arr = []; fib_arr[0] = 0; fib_arr[1] = 1; var fib = function(n){ // 递归中尽量短,避免不必要的变量和语句 if( typeof fib_arr[n] === 'number'){ return fib_arr[n]; } fib_arr[n] = fib( n - 1) + fib( n - 2); return fib_arr[n]; } return fib; }(); // 直接执行函数,返回 fib 保存到变量 fibonacci 中