如何在DFS后期遍历/折叠树

时间:2017-02-03 21:42:03

标签: javascript tree functional-programming depth-first-search tree-traversal

给出了这种树数据结构:

const tree = {v:"f", c:[
  {v:"b", c:[
    {v:"a", c:[]},
    {v:"d", c:[
      {v:"c", c:[]},
      {v:"e", c:[]}
    ]}
  ]},
  {v:"g", c:[
    {v:"i", c:[
      {v:"h", c:[]}
    ]}
  ]}
]};

到目前为止,我已经设法使用尾递归方法在BFS和DFS预订中遍历它:

// tree fold

const foldl = concat => (valueKey, childKey) => f => acc => tree => {
  const next = (acc, [head, ...tail]) => head === undefined
   ? acc
   : next(
     f(acc) (head[valueKey]),
     concat(head[childKey]) (tail)
   );
    
  return next(acc, [tree]);
};


// auxilliary functions

const flip = f => x => y => f(y) (x);

const concat = xs => x => xs.concat(x);


// data

const tree = {v:"f", c:[
  {v:"b", c:[
    {v:"a", c:[]},
    {v:"d", c:[
      {v:"c", c:[]},
      {v:"e", c:[]}
    ]}
  ]},
  {v:"g", c:[
    {v:"i", c:[
      {v:"h", c:[]}
    ]}
  ]}
]};


// and run...

console.log("DFS pre-order", foldl(concat) ("v", "c") (concat) ([]) (tree) );
// yields ["f", "b", "a", "d", "c", "e", "g", "i", "h"]

console.log("BFS", foldl(flip(concat)) ("v", "c") (concat) ([]) (tree) );
// yields ["f", "b", "g", "a", "d", "i", "c", "e", "h"]

不幸的是,我无法调整方法,以便它可以另外处理DFS后期订单 - 可以说是一种统一的方法。所需的序列化为["a", "c", "e", "d", "b", "h", "i", "g", "f"]。任何帮助表示赞赏!

[编辑]

我设法实现了订购后的版本 - 但它仍然不是所有三种情况BFS,DFS预订,DFS后订单的统一解决方案。此外,我不认为我的方法特别优雅。所以我仍然对那些比我更了解递归的人的答案感兴趣。

const foldl = (valueKey, childKey) => f => acc => o => {
  const next = (acc, [head, ...tail]) => {
    // base case
    if (head === undefined) return acc;

    // branch (children)
    if (head[childKey].length > 0) {
      return next(
        acc,
        concat(head[childKey].concat({v:head[valueKey], c:[]})) (tail)
      );
    }

    // leaf (no children)
    return next(f(acc) (head[valueKey]), tail);
  };

  return next(acc, [o]);
};

foldl("v", "c") (concat) ([]) (tree);
// yields ["a", "c", "e", "d", "b", "h", "i", "g", "f"]

1 个答案:

答案 0 :(得分:0)

您需要在添加元素之前递归树,而不是尾递归:

function dfsPost(tree) {
   return tree.c.reduce((arr, el) => arr.concat(dfsPost(el)), []).concat(tree.v);
}

dfsPost(tree) // ["a", "c", "e", "d", "b", "h", "i", "g", "f"]

性能较差,但尾递归:您可以执行简单的DFS,但在迭代每个元素时,请使用c.reduceRight()。然后在结果数组上调用reverse()。

function dfsPost(tree) {
    return (function dfs(tree) {
         return [tree.v].concat(tree.c.reduceRight((arr, el) => arr.concat(dfs(el)), []))
    }(tree)).reverse();
}

dfsPost(tree) // ["a", "c", "e", "d", "b", "h", "i", "g", "f"]