js递归

本文深入探讨JavaScript中的递归,以阶乘函数为例,详细解析递归的实现方法,包括使用arguments.callee、命名函数表达式以及循环实现。同时,介绍了递归在树形结构数据处理和斐波那契数列中的应用,强调了递归的必要因素——递归方程和结束条件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

说到递归,就不得不说下阶乘了,阶乘函数是递归经典案例

阶乘的实现方法(一种递归,两种循环)

1.

{

function factorial(num) {

if (num <= 1) {

return 1;

}

else {

return num * factorial(num - 1);

}

}

console.log(factorial(3));

}

/如上面的代码所示,在函数有名字,而且名字以后也不会变的情况下,这样定义没有问题。但问题是这个函数的执行与函数名 factorial 紧紧耦合在了一起。为了消除这种紧密耦合的现象,可以像下面这样使用 arguments.callee。(非严格模式)

arguments.callee是一个指向正在执行的函数的指针,因此可以用它来实现对函数的递归调用

2.

{

function factorial(num) {

if (num <= 1) {

return 1;

}

else {

return num * arguments.callee(num - 1);

}

}

console.log(factorial(3));

}

在这个重写后的factorial()函数的函数体内,没有再引用函数名 factorial。这样,无论引用函数时使用的是什么名字,都可以保证正常完成递归调用。

{

let trueFactorial = factorial;

factorial = function () {

return 0;

};

console.log(trueFactorial(5)); //120

console.log(factorial(5)); //0

}

 但在严格模式下,不能通过脚本访问 arguments.callee,访问这个属性会导致错误。不过,可以使用命名函数表达式来达成相同的结果

3.

{

let factorial = (function f(num) {

if (num <= 1) {

return 1;

}

else {

return num * f(num - 1);

}

})

console.log(factorial(3));

}

4:for循环

{

function factorial(num) {

if (num < 0) {

return -1;

} else if (num === 0 || num === 1) {

return 1;

} else {

for (let i = num - 1; i >= 1; i--) {

num *= i;

}

}

return num;

};

console.log(factorial(5));

}

5:while循环

{

function factorial(num) {

var result = num;

if (num < 0) {

return -1;

} else if (num === 0 || num === 1) {

return 1;

} else {

while (num > 1) {

num--;

result *= num;

}

}

return result;

};

console.log(factorial(5));

}

6:尾递归

{

function factorial(n, total) {

if (n === 1) return total;

return factorial(n - 1, n * total);

}

console.log(factorial(5, 1)) // 120

}

 

阶乘是递归方法常见的一种,下面就来说说递归

递归:在一个函数通过名字调用自身的情况构成的

 js递归函数的应用

 1.树形结构数据

{

let root = {

name: 'D盘',

children: [

{

name: '学习',

children: [

{

name: '电子书',

children: [

{

name: '文学',

children: [

{

name: '茶馆'

},

{

name: '红与黑'

}

]

}

]

}

]

},

{

name: '电影',

children: [

{

name: '美国电影'

},

{

name: '日本电影'

}

]

}

]

};

// 遍历单个节点

let newArr = []

function traverseNode(node) {

newArr.push(node.name);

}



// 递归遍历树

function traverseTree(node) {

if (!node) {

return;

}

traverseNode(node);

if (node.children && node.children.length > 0) {

let i = 0;

for (i = 0; i < node.children.length; i++) {

this.traverseTree(node.children[i]);

}

}

}

traverseTree(root);

console.log(newArr)

}

另一个案例

 输出规则:

 如果上层isOpen: true, 则处理它的children数据,并把children数据单独合数组,插入大树组中,以此类推。

 基本输出结构如下

 [[旅游, 交通,家居], [国内游, 境外游], [西藏, 厦门]]

 let data = [
                {
                    title: "旅游",
                    isOpen: true,
                    children: [
                        {
                            title: "国内游",
                            isOpen: true,
                            children: [
                                {
                                    title: "西藏",
                                    isOpen: false,
                                }, {
                                    title: "厦门",
                                    isOpen: false,
                                }
                            ]
                        },
                        {
                            title: "境外游",
                            isOpen: false,
                            children: [
                                {
                                    title: "日本",
                                    isOpen: false,
                                }, {
                                    title: "澳大利亚",
                                    isOpen: false,
                                }
                            ]
                        }
                    ]
                },
                {
                    title: "交通",
                    isOpen: false,
                    children: [
                        {
                            title: "汽车",
                            isOpen: false,
                        }, {
                            title: "摩托车",
                            isOpen: false,
                        }
                    ]
                },
                {
                    title: "家居",
                    isOpen: false,
                }
            ]

           // 遍历单个节点
            let newArr = []
            function traverseNode(node) {
                let temp = [];
                for (i = 0; i < node.length; i++) {
                    temp.push(node[i].title);
                }
                newArr.push(temp)
            }
            // 递归遍历树
            function traverseTree(node) {
                if (!node) {
                    return;
                }
                traverseNode(node);
                for (let j = 0; j < node.length; j++) {
                    if (node[j].children && node[j].children.length > 0) {
                        if (node[j].isOpen == true) {
                            this.traverseTree(node[j].children);
                        }
                    }
                }
            }
            traverseTree(data);
            console.log(newArr);


          let resultList=[]
          function deal(data){
          let temp=[]
          data.forEach(({title}) => temp.push(title))
          resultList.push(temp)
          data.forEach(({isOpen,children})=>isOpen&&deal(children))
         }
         deal(data)
         console.log(resultList)  

 

2.Fibonacci数列第N项

// 递归实现

{

let fib = function (n) {

if (n <= 2) {

return 1;

}

return fib(n - 1) + fib(n - 2);

}

console.log(fib(10));

}

// 循环实现

{

let fib = function (n) {

let a1 = 1, a2 = 1, a3 = 0;

if (n <= 2) {

return 1;

}

for (var i = 0; i < n - 1; i++) {

a3 = a1 + a2;

a1 = a2;

a2 = a3;

}

return a3;

}

console.log(fib(5));


}

// 3.一共10级楼梯,每次可以走一步或两步,求一共多少种走法。得到公式,也就是斐波那契数列。n>2:f(n-1)+f(n+2)
 

{

let fib = function (n) {

if (n == 1) {

return 1;

} else if (n == 2) {

return 2;

} else if (n > 2) {

return fib(n - 1) + fib(n - 2);

}

}

console.log(fib(10));


}

 总结总结:

 递归的两个必要因素:

     递归方程,递归结束条件。

算法核心: 在有限次可预见性结果中,找到结果与上一次结果之间的关系。关键在于梳理清楚本次结果和上一次结果的关系有哪些方面或是因素。在草稿纸上写出前几次的结果,或者画图,这样更容易找到规律,这种规律实际上就是递归方程。在算法的分析中,当一个算法中包含递归调用时,其时间复杂度的分析会转化成为一个递归方程的求解

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值