共计 765 个字符,预计需要花费 2 分钟才能阅读完成。
前端也要懂算法,阅《算法图解》有所得。
一、递归
递归简而言之就是函数调用自己。比如说我们需要遍历一个文件夹,有 2 种思路:
循环
递归
2 种实现方式就不细说,
二、基线条件和递归条件
假设我们要写一个倒计时:
var a = 5;
cutdown= function(i){
i-=1
cutdown(i)
}
cutdown(a);
没错,上面的代码是个死循环。每个递归都需要有 2 个条件,一个是基线条件,用于控制递归啥时候暂停,一个是递归条件,控制调用自己的方式。下面我们把倒计时函数改造一下:
cutDown = function (i){
if(i === 1){// 基线条件
return
} else {// 递归条件
i-=1;
cutDown(i)
}
}
三、栈
1. 调用栈
调用栈就是我们调用一个函数的时候,计算机会单独分配一个内存块,用于存储函数的参数和变量,而如果我们调用多个函数,那么就会被分配多个内存块,每个内存块被压入栈中,最先调用的被压在最底层,而最后压入的最先执行完被弹出。因此,我们可以得出结论:
栈只有压入和弹出 2 个操作
栈的元素是先入后出的
每一个函数执行都会被分配一个内存块
同一个上下文的多个函数调用产生的内存块会被压入栈中。
2. 递归调用栈
递归的实现就是依赖栈的特性,比如我们需要算 5 的阶乘:
var func = function(i){
if(i === 1){
return 1;
}else{
return i*func(i-1);
}
}
// 执行 func(5)
// 入栈
func(5); // 此时 i = 5 被压入栈中
// 经过基线条件和递归条件,func(5) 暂停,func(4) 执行
func(4) ‘// 此时 i = 4 被压入栈中
…
func(1)
// 出栈
func(1) // 执行完毕后, 弹出,返回 1
// 上一个 func(2) 中的 func(i-1) 返回 1
func(2) // 返回 2X1= 2
…
func(5)