迭代树序列化功能

时间:2019-05-01 09:01:35

标签: javascript algorithm loops recursion tree

以下是我正在使用的树以及所需的字符串序列化的直观表示形式:

enter image description here

这是一个递归解决方案:

function* serialize(root) {
  if (root.length === 0)
    return;

  const [x, xs] = root;
  yield x;

  for (let i = 0; i < xs.length; i++)
    yield* serialize(xs[i]);

  yield ")";
}

const Node = (x, ...xs) => ([x, xs]);

const tree = Node("a",
  Node("b",
    Node("e"),
    Node("f",
      Node("k"))),
  Node("c"),
  Node("d",
    Node("g"),
    Node("h"),
    Node("i"),
    Node("j")));

console.log(
  Array.from(serialize(tree)).join("")); // abe)fk)))c)dg)h)i)j)))

显然,它可以工作,但对于非常深的树来说并不安全。如何将其转换为迭代的对应项?

我知道我需要一个堆栈。但我不知道细节。我对这种转换的基本机制特别感兴趣。

我设法创建了一个迭代的预遍历,但是奇怪的是,这对迭代序列化没有帮助:

const Node = (x, ...xs) => ([x, xs]);

const tree = Node("a",
  Node("b",
    Node("e"),
    Node("f",
      Node("k"))),
  Node("c"),
  Node("d",
    Node("g"),
    Node("h"),
    Node("i"),
    Node("j")));

function* preOrderIt(root) {
  if (root.length === 0)
    return;

  const stack = [root];

  while (stack.length > 0) {
    let [x, xs] = stack.pop();

    for (let i = xs.length - 1; i >= 0; i--)
      stack.push(xs[i]);

    yield x;
  }
}

console.log(
  Array.from(preOrderIt(tree)).join("")); // abefkcdghij

3 个答案:

答案 0 :(得分:2)

您的序列化基本上向每个节点添加了一个额外的虚拟子节点,因此您在迭代时必须“访问”它:

const Node = (x, ...xs) => ([x, xs]);

const tree = Node("a",
  Node("b",
    Node("e"),
    Node("f",
      Node("k"))),
  Node("c"),
  Node("d",
    Node("g"),
    Node("h"),
    Node("i"),
    Node("j")));

function* preOrderIt(root) {
  if (root.length === 0)
    return;

  const stack = [root];

  while (stack.length > 0) {
    let [x, xs] = stack.pop();

    if (x !== ')')             // <-
      stack.push([')', []]);   // <-

    for (let i = xs.length - 1; i >= 0; i--)
      stack.push(xs[i]);

    yield x;
  }
}



console.log(
  Array.from(preOrderIt(tree)).join(""));

答案 1 :(得分:1)

一种不同的方法,通过对级别使用数组并首先迭代更深的级别。

function s(root) {
    var i = 0,
        node,
        levels = [[root]],
        result = '';

    while (i !== -1) {
        [node, ...levels[i]] = levels[i];
        if (node) {
            result += node[0];
            if (node[1].length) {
                levels[++i] = node[1];
                continue;
            }
        } else {
            i--;
        }
        result += ')';
    }
    return result.slice(0, -1); remove extra bracket for the outer missing array
}

const
    node = (x, ...xs) => ([x, xs]),
    tree = node("a", node("b", node("e"), node("f", node("k"))), node("c"), node("d", node("g"), node("h"), node("i"), node("j"))),
    result = s(tree);

console.log(result);

答案 2 :(得分:0)

一种选择是链接节点。这样一来,您就可以遍历树而无需保持位置不变

  const Node = (value, ...children) => {
   const node = { value, children };
   children.forEach(child => child.parent = node);
   if(children.length > 1) 
      children.reduceRight((curr, prev) => ((prev.next = curr), prev));
   return node;
 };

这有什么帮助?好吧:

function serialize(node) {
  let result = node.value;
  while(node) {
    // Deep first
    while(node.children[0]) {
      node = node.children[0];
      result += node.value;
    }

    // then right
    if(node.next) {
      node = node.next;
      result += ")" + node.value;
    } else {
      // and up at the last node
      while(node && !node.next) {
        node = node.parent;   
        result += ")";
       }
       result += ")";
       if(node) {
        node = node.next;
        result += node.value;
       }
     }
   }
   return result;
 }