什么是递归?
递归函数是在一个函数内通过名字调用自身的情况下构成的。
递归的优点
递归可以用来处理循环解决起来比较麻烦的问题
方法:
1,函数自己调用自己
2,找规律,找出这一次和上一次的关系
2,需要一个出口条件,不能无限递归下去
1,计算阶乘
什么是阶乘?阶乘是表示从1到该数之间所有正整数的乘积。例如5的阶乘就是5*4*3*2*1,其它的数以此类推。
function factorial(num){//出口条件是num小于等于1if(num<=1){return 1}else {return num*factorial(num-1)}}console.log(factorial(5))//输出结果为120//对执行过程进行分析/*factorial(5)return factorial(4)*5 24*5=120return factorial(3)*4 6*4=24return factorial(2)*3 2*3=6return factorial(1)*2 1*2=2return 1* */
2,斐波那契数列
斐波那契数列是一个经典的数学序列,其特点是每个数字都是前两个数字之和。通常用F(n)表示第n个斐波那契数。数列的前几项通常为0, 1, 1, 2, 3, 5, 8, 13, 21, …等等,既后一个数是前两个数之和。
function fib(n) {//出口条件为n小于3if(n<3){return 1}else{return fib(n-1)+fib(n-2)}}console.log(fib(7))//过程分析/*return fib(6)+fib(5) 7+5=13return fib(5)+fib(3) 4+3=7return fib(3)+fib(1) 3+1=4* */
3,使用递归求和
function sum3(num){if(num==1){return 1}else {return num+sum3(num-1)}}console.log(sum3(10))//输出 55
在控制台调试可以看到,每一次调用自身就会先入栈,最终根据先进后出的原则返回,最终返回结果。
4,使用递归对数组进行拍平
<script>//对数据进行拍平function flattenArray(arr) {let result = [];for (let i = 0; i < arr.length; i++) {if (Array.isArray(arr[i])) {//递归调用来处理嵌套函数result = result.concat(flattenArray(arr[i]));} else {result.push(arr[i]);}}return result;}// 测试let newArray = [1, [2, [3, 4,[5,6,[7,8]]], 9], 10];console.log(flattenArray(newArray)); // 输出: [1, 2, 3, 4, 5, 6,7,8,9,10]
</script>
遍历传入的数组。如果数组中的某个元素是另一个数组,就递归调用flattenArray
函数来拍平那个子数组,并将结果连接到result
数组中。如果元素不是数组,就直接将其添加到result
数组中。最后返回result
数组,它包含了原数组的所有元素,返回的结果是已经拍平的一维数组。
5,使用递归拼接树形结构
<script>const list = [{ id: 1, name: 'Node 1', parentId: null },{ id: 2, name: 'Node 1.1', parentId: 1 },{ id: 3, name: 'Node 1.2', parentId: 1 },{ id: 4, name: 'Node 2', parentId: null },{ id: 5, name: 'Node 2.1', parentId: 4 },{ id: 6, name: 'Node 2.2', parentId: 4 }];function buildTree(list, parentId = null) {let tree = [];for (let item of list) {if (item.parentId === parentId) {const children = buildTree(list, item.id);if (children.length) {item.children = children;}tree.push(item);}}return tree;}// 生成树形结构const tree = buildTree(list);console.log(tree);
</script>
首先遍历所有节点,并检查每个节点的parentId
是否等于当前的parentId
参数。如果相等,我们就递归调用buildTree
函数。并将返回的子节点数组赋值给当前节点的children
属性。然后将当前节点添加到tree
数组中。最后,返回tree
数组。
6,递归的缺点
-
调用栈限制:递归函数在每次调用时都会在在栈上创建一个新的栈帧。如果递归深度过大,可能会超出调用栈的最大限制,导致“栈溢出”错误(
StackOverflowError
)。 -
性能问题:递归通常比迭代更消耗资源,因为每次递归调用都会涉及函数调用的开销,包括参数传递、栈帧的创建和销毁等。在性能敏感的应用中,递归可能不是最佳选择。
-
代码可读性:递归函数通常比迭代函数更难理解和调试。递归逻辑可能不如迭代直观,特别是当递归涉及多个分支或复杂条件时。这可能导致代码维护困难,增加出错的可能性。
-
不易于调试:递归函数在调试时可能会比较困难,因为函数调用栈可能非常深,使得跟踪和理解问题的根源变得复杂。