圆括号中的树

时间:2019-12-26 19:18:22

标签: algorithm tree

我必须从平衡的括号中找到树的高度并找到保护编号(或仅生成树)。 例如:
()()()()创建树,就像一个高度为3的列表。
我不知道如何将括号转换为树。我找到了一些“答案”:
http://www.cs.utsa.edu/~wagner/knuth/fasc4a.pdf(第二页包含具有4个节点的树的所有示例)
段落-二叉树,森林,非交叉对:
https://sahandsaba.com/interview-question-generating-all-balanced-parentheses.html
但是,我仍然不知道如何从这样定义的括号创建树。我觉得在Knuth中,作者将其视为显而易见的东西。
我想念某件事还是不是那么简单?
有必要先创建一个森林然后再创建一个二叉树吗?

2 个答案:

答案 0 :(得分:2)

一对圆括号代表一个节点。这些括号中的 中出现的内容表示其左子节点的子树(根据相同的规则)。这些括号右边显示的是该节点的右子节点的子树(同样,按照相同的规则)。

此编码可以转换为二叉树,如下所示:

function makeBinaryTree(input):
    i = 0 # character index in input

    function recur():
        if i >= input.length or input[i] == ")":
            i = i + 1
            return NIL
        i = i + 1            
        node = new Node
        node.left = recur()
        if i >= input.length or input[i] == ")":
            i = i + 1
            return node
        node.right = recur()
        return node

    return recur()

这是JavaScript中的一个实现,它对那些4节点树进行转换,并漂亮地打印出结果树:

function makeBinaryTree(input) {
    let i = 0; // character index in input
    return recur();
    
    function recur() {
        if (i >= input.length || input[i++] === ")") return null;
        let node = { left: recur(), right: null };
        if (i >= input.length || input[i] === ")") {
            i++;
            return node;
        }
        node.right = recur();
        return node;
    }
}

// Helper function to pretty print a tree
const disc = "\u2B24";
function treeAsLines(node) {
    let left = [""], right = [""];
    if (node.left) left = treeAsLines(node.left);
    if (node.right) right = treeAsLines(node.right);
    while (left.length < right.length) left.push(" ".repeat(left[0].length));
    while (left.length > right.length) right.push(" ".repeat(left[0].length));
    let topLeft = "", topRight = "";
    let i = left[0].indexOf(disc);
    if (i > -1) topLeft = "┌".padEnd(left[0].length-i+1, "─");
    i = right[0].indexOf(disc);
    if (i > -1) topRight = "┐".padStart(i+2, "─");
    return [topLeft.padStart(left[0].length+1) + disc + topRight.padEnd(right[0].length+1)]
           .concat(left.map((line, i) => line + "   " + right[i]));
}

// The trees as listed in Table 1 of http://www.cs.utsa.edu/~wagner/knuth/fasc4a.pdf
let inputs = [
    "()()()()",
    "()()(())",
    "()(())()",
    "()(()())",
    "()((()))",
    "(())()()",
    "(())(())",
    "(()())()",
    "(()()())",
    "(()(()))",
    "((()))()",
    "((())())",
    "((()()))",
    "(((())))"
];

for (let input of inputs) {
    let tree = makeBinaryTree(input);
    console.log(input);
    console.log(treeAsLines(tree).join("\n"));
}

答案 1 :(得分:1)

如果我正确理解Knuth,则表示形式如下:一对匹配的括号表示一个节点,例如()= A.连续两对匹配的括号表示第二个节点是第一个的右子节点,例如()()= A->B。两对嵌入括号表示内部节点是外部节点的左子节点,即(())= B <-A。因此,()()()() = A-> B-> C-> D。

将括号转换为二叉树的可能算法是:

convert(parentheses):
  if parentheses is empty:
    return Nil

  root = Node()

  left_start = 1
  left_end = Nil

  open = 0
  for p = 0 to |parentheses|-1:
    if parentheses[p] == '(':
      open += 1
    else
      open -= 1

    if open == 0:
      left_end = p
      break

  root.left = convert(parentheses[left_start:left_end] or empty if index out of bound)
  root.right = convert(parentheses[left_end+1:] or empty if index out of bound)

  return root

它通过递归转换二进制树L <-A-> R中的括号(L)R来工作。

相关问题