貌似大部分语言中的递归都差不多, 之所以在题目加JS是由于搜了下后觉得网上用js来形貌这观点的不多, 简朴地说递归就是函数挪用本身的历程。下面的栗子能够很直观地展现递归的实行历程:
function rec(x){
if(x!==1){
console.log(x)
rec(x-1)
console.log(x)
}
}
rec(5) //输出为5 4 3 2 2 3 4 5
由这个栗子?可知:在递归挪用语句前的语句实行是平常递次, 然则递归挪用语句后的实行倒是相反的也就是说在递归还没有完成时,函数的输出效果临时被挂起,由于平常在计算机中,是以栈的情势来完成递归,这个历程以下:
5 rec(4) //第一级
5 4 rec(3) //第二级
5 4 3 rec(2) //第三级
5 4 3 2 rec(1) //第四级
console.log() 2 3 4 5 //以出栈情势输出效果
当递归完成时, 实行流最先处置惩罚上一级递归中的递归语句背面的语句, 在这里是输出当前变量console.log(x)
递归异常适用于雷同函数差别参数的迭代轮回。然则由于需要为每一级的递归拓荒内存所以递归的开支相对来说蛮大的, 在许多编程的语言中,关于递归的开支题目有个TCO优化(Tail Call Optimization)戳这篇博客相识更多?[翻译] JS的递归与TCO尾挪用优化
之所以想最少这篇博客,是由于近来看《算法与数据结构JavaScript形貌》(请拉黑此书,bug极多,极不引荐)中运用递归遍历二叉树的算法挺绕的, 写篇博客厘清下。
这里直接借用原书的代码(有编削), 以二叉树的的中序遍历为例:
// 节点对象的组织函数
function Node(data, left, right) {
this.data = data;
this.left = left;
this.right = right;
this.show = show;
}
function show() {
return this.data;
}
//二叉树的组织函数
function BST() {
this.root = null;
this.insert = insert;
this.inOrder = inOrder;
}
//插进去要领
function insert(data) {
var n = new Node(data, null, null);
if (this.root == null) {
this.root = n;
}
else {
var current = this.root;
var parent;
while (true) {
parent = current;
if (data < current.data) {
current = current.left;
if (current == null) {
parent.left = n;
break;
}
}
else {
current = current.right;
if (current == null) {
parent.right = n;
break;
}
}
}
}
}
//挪用两次递归遍历二叉树
function inOrder(node) {
if (!(node == null)) {
inOrder(node.left);
console.log(node.show() )
inOrder(node.right);
}
}
//将以下数据导入二叉树
nums.insert(23)
nums.insert(45)
nums.insert(16)
nums.insert(37)
nums.insert(3)
nums.insert(99)
nums.insert(22)
//中序遍历二叉树
inOrder(nums.root)
/*
输出效果为:
3
16
22
23
37
45
99
*/
在inOrder函数中运用了两次递归,它的实行递次是:沿左侧找到最小值3,第一次递归完成, 之前被挂起的语句最先以出栈的情势实行,输出无子节点的节点3,然后回到上一级递归,输出其上一级递归中的节点16, 在节点16处, 存在子节点,因而实行向右递归,实行到无子节点的22,输出22后返回到节点16 , 实行流继承往回实行, 实行到根节点23,输出23后又插进去一次向右递归,右递归到45, 存在左子节点,实行向左递归, 以此类推,就完成了这棵二叉树的中序遍历
附张遍历递次示意图: