简体   繁体   中英

How to traverse/fold a tree in DFS post-order

Given is this tree data structure:

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:[]}
    ]}
  ]}
]};

So far I've managed to traverse it in BFS and DFS pre-order with a tail recursive approach:

 // 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"] 

Unfortunately, I 'm not able to adapt the approach so that it can handle DFS post-order in addition - a unified approach, so to speak. The desired serialization is ["a", "c", "e", "d", "b", "h", "i", "g", "f"] . Any help is appreciated!

[EDIT]

I managed to implement the post-order version - but it still not a unified solution for all three cases BFS, DFS pre-order, DFS post-order. Besides, I don't think my approach is particularly elegant. So I'm still interested in answers from people who have a better understanding of recursion than me.

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"]

Instead of tail-recursion, you want to recurse down the tree before adding the elements:

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"]

Less performant, but tail recursive: You can do a simple DFS, but when iterating over each element, use c.reduceRight(). Then call reverse() on the resulting array.

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"]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM