【发布时间】:2015-03-03 06:49:48
【问题描述】:
以下函数返回从根节点到树最深节点的可能路径列表:
paths :: Tree a -> [[a]]
paths (Node element []) = [[element]]
paths (Node element children) = map (element :) $ concat $ map paths children
这在纸面上看起来非常低效,因为concat 具有可怕的复杂性。是否可以在不使用中间数据结构(如序列)的情况下以降低复杂性的方式重写此函数?
编辑:老实说,我知道可以通过以下方式避免 concat 的 O(n)/循环复杂性:
- 在递归过程中构建路径(列表);
- 仅当您到达最后一个递归级别时,才将路径附加到全局“结果”列表中。
这是一个说明此算法的 JavaScript 实现:
function paths(tree){
var result = [];
(function go(node,path){
if (node.children.length === 0)
result.push(path.concat([node.tag]));
else
node.children.map(function(child){
go(child,path.concat([node.tag]));
});
})(tree,[]);
return result;
}
console.log(paths(
{tag: 1,
children:[
{tag: 2, children: [{tag: 20, children: []}, {tag: 200, children: []}]},
{tag: 3, children: [{tag: 30, children: []}, {tag: 300, children: []}]},
{tag: 4, children: [{tag: 40, children: []}, {tag: 400, children: []}]}]}));
(实际上不是 O(1)/iteration,因为我使用 Array.concat 而不是列表 consing(JS 没有内置列表),但仅使用它会使其每次迭代的时间恒定.)
【问题讨论】:
-
DList应该模拟您描述的全局解决方案的性能 - 它的功能等同于改变列表 cons(只要它只被使用一次) -
...我不知道怎么做?我很想看到答案! :) 还有 - 如果你只是像这样使用列表单子:“do { x
标签: haskell recursion data-structures tree complexity-theory