[英]How to traverse a General Tree (not BST) recursively in JavaScript?
[英]Recursively traverse tree in Javascript
这是用Java做的超级简单的任务,但是javascript的异步性质使得这个任务(对我来说)几乎不可能,至少我现在的知识。(我不是想破坏javascript。喜欢这种语言!)。
这是非常基本的。 顶级树在我的mysql数据库中具有null的父级。 很容易找到孩子。 孩子们可以使用线路。 树的深度是可变的。
private static Set<Tree> getBranches( Tree trunk ) {
Set<Tree> treeSet = new HashSet<Tree>();
if ( trunk != null ) {
if ( trunk.hasLines() ) { //queries if tree has lines. returns true or false
treeSet.add( trunk );
}
for ( Tree tree : trunk.treeList ) {
treeSet.addAll( getBranches( tree ) );
}
}
return treeSet;
}
基本上该方法测试树是否有可用的线。 如果是这样,它会将所有这些添加到集合中。 如果没有,它会继续,直到找到线条。
mysql节点库的异步特性将此任务变为地狱。
这就是我现在拥有的
function hasLines(tree_id, callback) {
var ret;
pool.query('SELECT * from pkg_line_tree where tree_id = ?', [tree_id], function (err, rows) {
if (rows.length > 0) {
ret = true;
} else {
ret = false;
}
callback(ret);
});
}
function dig(tree_id, treeArray, callback) {
pool.query('SELECT * from tree where parent_id = ?', [tree_id], function (err, rows) {
if (rows) {
for (var i in rows) {
hasLines(rows[i].tree_id, function (t) {
if (t) {
treeArray.push(rows[i].tree_id);
} else {
treeArray.concat(dig(rows[i].tree_id, treeArray));
}
});
}
if (callback) {
callback(treeArray);
}
}
});
return treeArray;
}
var treeArray = [];
dig(52, treeArray, function (t) {
res.json(t);
});
我真的只需要输出这个根树中可用的所有子节点。
如果这没有意义,请告诉我。 我会尝试重构。 我希望我能得到某种观点。 我讨厌使用像Fibers这样的东西来完成这项任务,但我没有选择。 谢谢。
你必须使用async https://github.com/caolan/async
我修改了你的dig函数以使用async的forEach方法
function dig(tree_id, treeArray, AllDone) {
pool.query('SELECT * from tree where parent_id = ?', [tree_id], function (err, rows) {
if (rows) {
async.forEach(
rows,
function(row, callback) {
hasLine(row.tree_id, function(t){
if (t) {
treeArray.push(row.tree_id);
callback();
}
else {
dig(row.tree_id, treeArray, callback);
}
});
},
function(err) {
if (err) AllDone(err, treeArray);
else AllDone(null, treeArray);
});
}
else
AllDone(null, treeArray)
});
}
treeArray = [];
dig(52, treeArray, function(err, t) {
res.json(t);
});
假设rows是一个数组.. forEach
遍历每一行并执行hasLine,每次迭代都会在完成后调用callback
函数,并且在调用所有callback
函数时将调用AllDone
。 这里棘手的部分是递归,每个递归调用都有一个forEach
循环,只有当所有callbacks
都完成后才会调用AllDone
方法。
但是forEach
并行执行,所以订单不能保持
如果您不关心订单,我认为这应该有用。
编辑 : 您可以使用forEachSeries
来解决订单问题。
您对dig()
使用目前不一致:
// asynchronous with callback
dig(52, treeArray, function (t) {
res.json(t);
});
// then synchronous with `return`?
treeArray.concat(dig(rows[i].tree_id, treeArray));
此外,最后一行中的concat
实际上并没有做太多,因为它不会改变它所调用的数组。 你可能不会真的希望它为dig
绕过treeArray
而不是定义一个新treeSet
像getBranches
。 所以,如果确实如此,那么每次都会将treeArray
附加到自身的末尾。
您仍然可以将concat
与多个treeSet
一起使用,但您必须存储其return
值:
treeSet = treeSet.concat(subSet);
而且,你必须用异步迭代器替换for
循环,因为循环不会在继续之前等待异步操作。 如果你想尝试它, async
库有几个选项。
因此,使用多个treeSet
, concat
和async.forEachSeries
,您可以尝试:
function dig(tree_id, callback) {
var treeSet = [];
hasLines(tree_id, function (yep) {
if (yep) {
treeSet.push(tree_id);
}
pool.query('SELECT * from tree where parent_id = ?', [tree_id], function (err, rows) {
function each(row, next) {
dig(row.tree_id, function (subSet) {
treeSet = treeSet.concat(subSet);
next(null);
});
}
function done() {
callback(treeSet);
}
async.forEachSeries(rows, each, done);
});
});
}
dig(52, function (treeSet) {
res.json(treeSet);
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.