- 算法为王。
- 排序算法博大精深,前辈们用了数年甚至一生的心血研究出来的算法,更值得咱们学习与推敲。
由于以后要讲有内容和算法,其代码的实现都要用到递归,因此,搞懂递归很是重要。前端
简单来讲就是:本身调用本身。git
现实例子:周末你带着女友去电影院看电影,女友问你,我们如今坐在第几排啊 ?电影院里面太黑了,看不清,无法数,如今你怎么办 ?github
因而你就问前面一排的人他是第几排,你想只要在他的数字上加一,就知道本身在哪一排了。
可是,前面的人也看不清啊,因此他也问他前面的人。
就这样一排一排往前问,直到问到第一排的人,说我在第一排,而后再这样一排一排再把数字传回来。
直到你前面的人告诉你他在哪一排,因而你就知道答案了。算法
基本上,全部的递归问题均可以用递推公式来表示,好比:json
f(n) = f(n-1) + 1; // 其中,f(1) = 1
f(n) 表示你想知道本身在哪一排,f(n-1) 表示前面一排所在的排数,f(1) = 1 表示第一排的人知道本身在第一排。数组
有了这个递推公式,咱们就能够很轻松地将它改成递归代码,以下:浏览器
function f(n) { if (n == 1) return 1; return f(n-1) + 1; }
一个问题只要同时知足如下 3 个条件,就能够用递归来解决。数据结构
好比,前面讲的电影院的例子,你要知道,本身在哪一排
的问题,能够分解为前一排的人在哪一排
这样一个子问题。函数
好比电影院那个例子,你求解本身在哪一排
的思路,和前面一排人求解本身在哪一排
的思路,是如出一辙的。学习
好比电影院的例子,第一排的人不须要再继续询问任何人,就知道本身在哪一排,也就是 f(1) = 1,这就是递归的终止条件。
1. 递归代码编写
写递归代码的关键就是找到如何将大问题分解为小问题的规律,而且基于此写出递推公式,而后再推敲终止条件,最后将递推公式和终止条件翻译成代码。
2. 递归代码理解
对于递归代码,若试图想清楚整个递和归的过程,其实是进入了一个思惟误区。
那该如何理解递归代码呢 ?
所以,理解递归代码,就把它抽象成一个递推公式,不用想一层层的调用关系,不要试图用人脑去分解递归的每一个步骤。
function fact(num) { if (num <= 1) { return 1; } else { return num * fact(num - 1); } } fact(3) // 结果为 6
如下代码可致使出错:
var anotherFact = fact; fact = null; alert(antherFact(4)); //出错
因为 fact 已经不是函数了,因此出错。
使用 arguments.callee
arguments.callee 是一个指向正在执行的函数的指针,arguments.callee 返回正在被执行的对现象。
新的函数为:
function fact(num){ if (num <= 1){ return 1; }else{ return num * arguments.callee(num - 1); //此处更改了。 } } var anotherFact = fact; fact = null; alert(antherFact(4)); // 结果为 24
先看图
叶子结点:就是深度为 0 的结点,也就是没有孩子结点的结点,简单的说就是一个二叉树任意一个分支上的终端节点。
数据结构格式,参考以下代码:
const json = { name: 'A', children: [ { name: 'B', children: [ { name: 'E', }, { name: 'F', }, { name: 'G', } ] }, { name: 'C', children: [ { name: 'H' } ] }, { name: 'D', children: [ { name: 'I', }, { name: 'J', } ] } ] }
咱们如何获取根节点的全部叶子节点个数呢 ?
递归代码以下:
/** * 获取根节点的全部 叶子节点 个数 * @param {Object} json Object 对象 */ function getLeafCountTree(json) { if(!json.children){ return 1; } else { let leafCount = 0; for(let i = 0 ; i < json.children.length ; i++){ // leafCount = leafCount + getLeafCountTree(json.children[i]); leafCount = leafCount + arguments.callee(json.children[i]); } return leafCount; } }
递归遍历是比较经常使用的方法,好比:省市区遍历成树、多叉树、阶乘等。
JavaScript 数据结构与算法之美 的系列文章,坚持 3 - 7 天左右更新一篇,暂定计划以下表。
| 标题 | 连接 |
| :------ | :------ |
| 时间和空间复杂度 | https://github.com/biaochenxu... |
| 线性表(数组、链表、栈、队列) | https://github.com/biaochenxu... |
| 实现一个前端路由,如何实现浏览器的前进与后退 ?| https://github.com/biaochenxu... |
| 栈内存与堆内存 、浅拷贝与深拷贝 | https://github.com/biaochenxu... |
| 递归 | https://github.com/biaochenxu... |
| 非线性表(树、堆) | 精彩待续 |
| 冒泡排序 | 精彩待续 |
| 插入排序 | 精彩待续 |
| 选择排序 | 精彩待续 |
| 归并排序 | 精彩待续 |
| 快速排序 | 精彩待续 |
| 计数排序 | 精彩待续 |
| 基数排序 | 精彩待续 |
| 桶排序 | 精彩待续 |
| 希尔排序 | 精彩待续 |
| 堆排序 | 精彩待续 |
| 十大经典排序汇总 | 精彩待续 |
若是有错误或者不严谨的地方,请务必给予指正,十分感谢。
文章能够转载,但须注明做者及出处,须要转载到公众号的,喊我加下白名单就好了。
参考文章: