一、递归: 函数中调用函数自己,在使用递归的时候一定需要有结束递归的条件,否则就会变成死循环。
想要用递归必须知道两个条件:
1、递归出口(终止递归的条件) 2、递归表达式(规律)
技巧: 在递归中常常是将问题切割成两个部分(1和整体的思想),这能够让我们快速找到递归表达式(规律)
二、递归和循环的区别
简单来说,循环是有去无回,而递归则是有去有回(因为存在终止条件)。 举个栗子,你用你手中的钥匙打开一扇门,结果去发现前方还有一扇门,紧接着你又用钥匙打开了这扇门,然后你又看到一扇们…但是当你开到某扇门时,发现前方是一堵墙无路可走了,你选择原路返回——这就是递归 但是如果你打开一扇门后,同样发现前方也有一扇们,紧接着你又打开下一扇门…但是却一直没有碰到尽头——这就是循环。
三、实例
1、递归案例:求一个数字各个位数上的数字的和
function getEverySum(x) { if(x<10){ return x; } //获取的是这个数字的个位数 return x % 10 + getEverySum( parseInt( x/ 10 ) ); } console.log(getEverySum(987654321)); // 452、平铺多维数组
let arr = [ [1,2,], 3 ,4, [5, [6, [7 ,8, [9]]]]] let temp = [] function digui(arr) { for (let i = 0; i< arr.length; i++) { // 判断是不是数组,若是数组就在进行递归 if (dataType(arr[i]) === 'array') { digui(arr[i]) } else { // 不是数组直接push 进去 temp.push(arr[i]) } } } digui(arr) console.log(temp); // [1, 2, 3, 4, 5, 6, 7, 8, 9] // 判断数据类型 function dataType(obj) { let o = {} return o.toString.call(obj).slice(8,-1).toLowerCase() }2、求和
// for 求10以内数字的和 var sum=0 for ( var i =0; i < 10 ; i++ ) { sum = sum + i; } console.log(sum ); // 45 // 递归实现n个数字的和 function getSum (x) { if ( x ==1 ) { return 1; } return x + getSum ( x - 1 ); } console.log(getSum( 10 - 1 )); // 453、获取数组中的最大值
let array = [1, 11,11,115,115]; console.log(getMax(array,0,array.length - 1 )); // 115 /** * 递归,找出数组最大的值 * @param arr数组 * @param left 左边界,第一个数 * @param right 右边界,数组的长度 * @return */ function getMax(arr, left, right) { // left数组第一个元素 // right赋值为array.length-1 // 如果该数组只有一个数,那么最大的就是该数组第一个值了 if (left === right) { return arr[left]; } else { let a = arr[left]; //找出整体的最大值 let b = getMax(arr, left + 1, right); if (a > b) { return a; } else { return b; } } }4、汉诺塔玩法 // 汉诺塔的规则 // 有三根柱子,原始装满大小不一的盘子的柱子我们称为A,还有两根空的柱子,我们分别称为B和C(任选) // 最终的目的就是将A柱子的盘子全部移到C柱子中 // 移动的时候有个规则:一次只能移动一个盘子,小的盘子不能在大的盘子下面(反过来:大的盘子不能在小的盘子上面)
console.log("bar1-- 有三个盘"); towersofHanoi(3, 'bar1', 'bar2', 'bar3'); * 汉诺塔 * @param n n个盘子 * @param start 起始柱子 * @param transfer 中转柱子 * @param target 目标柱子 * function towersofHanoi( n, start, transfer, target) { //只有一个盘子,直接搬到目标柱子 if (n === 1) { console.log(start + "---->" + target); } else { //起始柱子借助目标柱子将盘子都移动到中转柱子中(除了最大的盘子) towersofHanoi(n - 1, start, target, transfer); console.log(start + "---->" + target); //中转柱子借助起始柱子将盘子都移动到目标柱子中 hanoi(n - 1, transfer, start, target); } }5、冒泡排序递归写法
冒泡排序:俩俩交换,在第一趟排序中能够将最大值排到最后面,外层循环控制排序趟数,内层循环控制比较次数 以递归的思想来进行改造: 当第一趟排序后,我们可以将数组最后一位(right)和数组前面的数(left,right-1)进行切割,数组前面的数(left,right-1)看成是一个整体,这个整体又是和我们的初始目的(找出最大值,与当前趟数的末尾处交换)是一样的 递归出口:当只有一个元素时,即不用比较了:left === right let arrays = [2, 3, 4, 5, 1, 5, 2, 9, 5, 6, 8, 3, 1] bubbleSort(arrays, 0, arrays.length - 1) console.log(arrays) // [1, 1, 2, 2, 3, 3, 4, 5, 5, 5, 6, 8, 9] function bubbleSort(arr, left, right ) { let temp; //如果只有一个元素了,那什么都不用干 if (left === right) { } else { for (let i = left; i < right; i++) { if (arr[i] > arr[i + 1]) { temp = arr[i]; arr[i] = arr[i + 1]; arr[i + 1] = temp; } } //第一趟排序后已经将最大值放到数组最后面了 //接下来是排序"整体"的数据了 bubbleSort(arr, left, right - 1); } }