给出以下算法:
console.log(JSON.stringify(create(0), null, 2))
function create(i) {
if (i == 5) return
return new Klass(i, create(i + 1), create(i + 1))
}
function Klass(i, l, r) {
this.i = i
this.l = l
this.r = r
}
在创建所有子项后,以递归方式在Klass
last 中创建create(0)
。因此,它首先创建叶节点,然后将其传递给父节点等。
想知道如何使用没有递归的堆栈来执行此操作。让我的头受伤:)我理解如何使用堆栈从上到下创建,但不是自下而上。自上而下,基本上是这样的:
var stack = [0]
while (stack.length) {
var i = stack.pop()
// do work
stack.push(children)
}
自下而上,我看不出它应该如何运作。这就是我陷入困境的地方:
function create(i) {
var stack = []
stack.push([i, 'open'])
stack.push([i, 'close'])
while (stack.length) {
var node = stack.pop()
if (node[1] == 'open') {
stack.push([ node[0] + 1, 'open' ])
stack.push([ node[0] + 1, 'close' ])
} else {
// ?? not sure how to get to this point
var klass = new Klass(node[0], node[2], node[3])
// ??
}
}
}
答案 0 :(得分:3)
将任何递归代码机械转换为堆栈机器并非易事。自动状态转换产生非常复杂的代码,只需考虑C#-s或BabelJS-s生成器。但可以肯定的是,它可以完成,但是你需要可变的堆栈帧和/或寄存器。让我们看看我们面临的问题:
我们必须在堆栈本身上存储一些状态变量/指令指针。这是您使用"open"
和"close"
标记进行模拟的内容。
有很多方法:
out
参数使用可变堆栈帧和结果寄存器,转换后的代码看起来像这样:
console.log(JSON.stringify(create(0), null, 2))
function Klass(i, l, r) {
this.i = i
this.l = l
this.r = r
}
function Frame(i) {
this.ip = 0;
this.i = i;
this.left = null;
}
function create(i) {
var result;
var stack = [new Frame(i)];
while (stack.length > 0) {
var frame = stack[stack.length - 1];
switch (frame.ip) {
case 0:
if (frame.i === 5) {
result = undefined;
stack.pop();
break;
}
stack.push(new Frame(frame.i + 1));
frame.ip = 1;
break;
case 1:
frame.left = result;
stack.push(new Frame(frame.i + 1));
frame.ip = 2;
break;
case 2:
result = new Klass(frame.i, frame.left, result);
stack.pop();
break;
}
}
return result;
}
答案 1 :(得分:2)
这是一个使用两个堆栈的解决方案。
假设我们总是在离开孩子之前计算出正确的孩子,我们需要一种方法来存储对孩子的结果。可以将它存储在原始堆栈上,但它会很复杂,因为该堆栈也用于计算左子。所以我使用另一个堆栈来存储正确孩子的结果。
有三种状态:
当它看到状态为finish work
的节点时,它会检查下一个节点
节点的状态为need merge
:
finish work
console.log(JSON.stringify(create(2, 5), null, 2))
function Klass(i, l, r) {
this.i = i;
this.l = l;
this.r = r;
}
function create(i, growto) {
var stack = [];
var cache = [];
stack.push([i, 'need work']);
while (stack.length && stack[0][1] !== 'finish work') {
var cur = stack.pop();
var val = cur[0];
var status = cur[1];
if (status === 'need work') {
if (val !== growto) {
stack.push([val, 'need merge']);
stack.push([val + 1, 'need work']);
stack.push([val + 1, 'need work']);
} else {
stack.push([val, 'finish work']);
}
} else if (status === 'finish work') {
if (stack[stack.length - 1][1] !== 'need merge') {
cache.push(cur);
} else {
var root = stack.pop()[0];
var left = cur[0];
var right = cache.pop()[0];
stack.push([new Klass(root, left, right), 'finish work']);
}
}
}
return stack.pop()[0];
}

答案 2 :(得分:0)
这样的事情:
console.log(JSON.stringify(create(4), null, 2))
function create(depth) {
let n = Math.pow(2, depth);
let nodes = [];
for (let i = 0; i < n; i++)
nodes.push(new Klass(depth));
for (depth--; depth >= 0; depth--) {
let next = [];
while (nodes.length > 0)
next.push(new Klass(depth, nodes.pop(), nodes.pop()));
nodes = next;
}
return nodes[0];
}
function Klass(i, l, r) {
this.i = i
this.l = l
this.r = r
}
&#13;
获得相同结果的调用将是create(4);
。它不是完全相同的创建顺序,它从下到上创建节点,而递归就像:
7
3 6
1 2 4 5
您还可以使用堆栈模仿此行为:
console.log(JSON.stringify(create(4), null, 2))
function create(depth) {
let stack = [{depth: 0}]
for (;;) {
let i = stack.length - 1
let cur = stack[i]
if (typeof cur.left === 'undefined') {
if (cur.depth < depth) {
stack.push({depth: cur.depth + 1, parent: i, pos: 'right'})
stack.push({depth: cur.depth + 1, parent: i, pos: 'left'})
} else {
stack[cur.parent][cur.pos] = new Klass(cur.depth)
stack.pop()
}
} else {
let node = new Klass(cur.depth, cur.left, cur.right)
if (cur.depth == 0)
return node
stack[cur.parent][cur.pos] = node
stack.pop()
}
}
}
function Klass(i, l, r) {
this.i = i
this.l = l
this.r = r
}
&#13;
首先在堆栈上推送右节点,然后在左节点上推送,以便左侧节点在堆栈中更高并首先处理。
答案 3 :(得分:0)
让我们从i
s开始:
function create(i) {
console.log(i)
if (i == 3) return
return new Klass(i, create(i+1), create(i+1))
}
function Klass(i, l, r) {
this.i = i
this.l = l
this.r = r
}
console.log(JSON.stringify(create(0)))
console.log('\nStack version:')
let stack = [0];
while (stack.length){
let i = stack.pop();
console.log(i);
if (i < 3)
stack.push(i + 1, i + 1);
}
&#13;
有很多方法可以使用i
s的迭代生成顺序;从把它们全部推到一个阵列,然后跟踪任务向后;使用i
创建一个新的Klass并通过引用传递它,基本上将过程变为自上而下。