【问题标题】:How to construct a binary tree from just the level order traversal string如何仅从级别顺序遍历字符串构造二叉树
【发布时间】:2013-12-23 13:03:54
【问题描述】:

考虑具有以下属性的二叉树:

  1. 如果内部节点(非叶节点)有两个子节点,则其值为 1。
  2. 叶节点的值为 0,因为它没有子节点。

树上的级别顺序遍历将生成一串 1 和 0(通过在每个节点被访问时打印奇怪的值)。现在给定这个字符串构造二叉树并在树上执行后序遍历。 post order 字符串应该是程序的输出。

例如:输入字符串为111001000。以此创建二叉树。然后在树上执行后序遍历,这将导致输出:001001011

问题的“症结”是仅从级别顺序字符串创建二叉树。我该怎么做?

【问题讨论】:

  • 一个只有 1 个子节点的非叶节点 - 它有什么价值?
  • 没有只有 1 个子节点的节点。它要么有两个孩子,要么没有孩子。

标签: java binary-tree tree-traversal postorder


【解决方案1】:

以你的水平顺序遍历为例 - 111001000 树将如下所示

      A
    /   \ 
   B     C
  /\     /\
 D  E   F  G
       /\
      H  I

逻辑如下。

1) 如果它的 1(根)取第一位 - 然后下一个 2^1 是该父项的子项的值。所以第 2 位和第 3 位是 A(根)的子节点。

2) 转到下一位(1 代表 B),因为它的值也是 1,它也有 2 个孩子,然后下一位(1 代表 C)也有 2 个孩子。第二级已经结束,因为我们有 2 个 1,所以 2^2 下一个位用于第 3 级。

3) 111 001000 所以我们已经遍历过了,接下来的 4 位是第三级的子级。第 4 位和第 5 位为 0(D 和 E 是叶节点,没有子节点 - 这些将是 B 的子节点),然后 F 的位值为 1,因此 1110010 00 (粗体数字)将是子节点F的第7位为0,所以G也将是叶子节点。

4) 再次循环或尝试 recusion - 从第 4、5、6 和 7 位开始,只有一位为 1,因此接下来的 2^1 位将在下一级,这些将是 F 的子级。

创建树后,转换为 PostFix 就很容易了。

【讨论】:

【解决方案2】:

一种可能的解决方案(不到一小时):

import java.util.ArrayList;
import java.util.List;

public class Main {

    private static class Node {
        private Node left;
        private Node right;
    }

    private static Node buildTree(String input) {
        char chars[] = input.toCharArray();
        if (chars.length == 0) {
            return null;
        } else {
            Node root = new Node();
            List<Node> nodeList = new ArrayList<Node>();
            nodeList.add(root);
            int pos = 0;
            while (!nodeList.isEmpty()) {
                List<Node> nextList = new ArrayList<Node>();
                for (Node n: nodeList) {
                    if (pos >= chars.length) {
                        throw new RuntimeException("Invalid input string");
                    }
                    char c = chars[pos++];
                    if (c == '1') {
                        n.left = new Node();
                        n.right = new Node();
                        nextList.add(n.left);
                        nextList.add(n.right);
                    } else if (c != '0') {
                        throw new RuntimeException("Invalid input string");
                    }
                }
                nodeList = nextList;
            }
            return root;
        }
    }

    private static String postTraverse(Node n) {
        if (n == null) {
            return "";
        } else if (n.left == null && n.right == null) {
            return "0";
        } else {
            return postTraverse(n.left) + postTraverse(n.right) + "1";
        }
    }

    public static void main(String[] args) {
        Node tree = buildTree(args[0]);
        System.out.println(postTraverse(tree));
    }
}

【讨论】:

    【解决方案3】:

    如果允许,我会在这里使用二进制堆作为助手。在使用标准表实现的二叉堆中,给定元素的索引,我们可以轻松计算其父元素的索引:int parent = (index-1)/2;。知道了这一点,我们需要从表格的开头开始并执行以下操作:

    1. 将 binaryHeap[0] 设置为输入流中的第一个数字;
    2. 对于输入流中的所有剩余元素:

        do{
           binaryHeap[heapIndex] = -1;
           if (parent(heapIndex) = 1)
                 binaryHeap[heapIndex] = nextElementFromTheInputStream;
           heapIndex++;
        }
        while(binaryHeap[heapIndex - 1] == 0);
      

    所以基本上,我们在桌子上移动。我们将每个字段(除了 0 的根)初始化为 -1,这意味着那里没有节点。然后我们检查该字段的父级是否为 1。如果是,则我们将输入流中的下一个元素放在堆中的当前索引 (heapIndex) 上。如果当前字段的父级为 0,我们就走得更远,因为这意味着我们的父级是一片叶子,不应该有任何子级。

    然后我们可以在堆上运行后排序算法(可能值得实现一些安全代码,这样就不会在输出流中放置带有“-1”的元素。只需解释 leftChild(heapIndex) == -1; 或 rightChild(heapIndex) == -1; 为 NULL)。

    这个算法在内存方面可能效率很低,但我希望它很容易理解。

    【讨论】:

      【解决方案4】:

      首先,我假设您的 level order traversal 基本上是一个 BFS。

      现在,让我们看一下字符串。执行 BFS,如果当前节点有两个儿子,我们打印“1”。否则,它是一个叶子,我们打印 0,终止当前分支的处理。

      因此,在反向任务期间,我们可以记住打开分支的最后一个节点的列表,并将传入的节点附加到那里。

      让我们通过一个例子来演示这种方法:

      Level 1:
      
      Tree :   
              1 - id 0
      Open branches : 0 0 (left and right son)
      Remaining string : 11001000
      
      *********
      
      Level 2:
      
      Tree :   
              1
            1    1 
      Open branches : 1 1 2 2
      Remaining string : 001000
      
      *********
      
      Level 3:
      
      Tree : 
             1
          1     1
         0  0  1  0
      
      Open branches : 5 5
      
      Remaining string : 00
      
      
      Level 4:
      
      Tree : 
             1
          1     1
         0  0  1  0
              0 0
      
       No more input, we're done.
      

      有了树,后序遍历就很简单了。

      还有代码(假设树非常密集,否则内存效率不是很高):

      import java.util.ArrayDeque;
      import java.util.Queue;
      
      public class Main {
      static final int MAX_CONST = 50;
      
      public static void main(String[] args) {
          String evilString = "111001000"; // Assuming this string is a correct input
      
          char[] treeRepr = new char[MAX_CONST];
          Queue<Integer> q = new ArrayDeque<Integer>();
          q.add(0);       
          for (int i = 0; i < evilString.length(); ++i) {
              int index = q.remove();
              char ch = evilString.charAt(i);
              if (ch == '1') {
                  q.add(2*(index+1)-1);
                  q.add(2*(index+1));
              }
              treeRepr[index] = ch;
              // System.out.println(q.size());
          }   
          System.out.println(arrToString(treeRepr, 0, new StringBuilder()));
      }
      
      public static StringBuilder arrToString(char[] array, int index, StringBuilder sb) {
          if (array[index] == '1')
          {
              arrToString(array, 2*(index+1)-1, sb);
              arrToString(array, 2*(index+1), sb);
          }
          sb.append(array[index]);
          return sb;
      }
      }
      

      【讨论】:

        【解决方案5】:

        这是一个非常简单的解决方案。
        并不是最理想的 不过,尊重记忆,因为我首先构建了一个完整/完整的树
        然后我标记我们的树中实际存在哪些节点。所以这个
        可以优化一下,我猜。

            import java.util.HashMap;
            import java.util.LinkedList;
            import java.util.Queue;
        
            class Node {
                public Node left;
                public Node right;
                public Integer id;
                public boolean exists;
            }
        
            public class Test32 {
        
                public static void main(String[] args) {
                    HashMap<Integer, Node> mp = new HashMap<Integer, Node>();
        
                    String str = "110101000";
                    int sz = (int)Math.pow(2, str.length() + 1);
        
                    for (int i=0; i<sz; i++){
                        Node nd = new Node();
                        nd.id = i;
                        mp.put(nd.id, nd);
                    }
        
                    for (int i=0; i<sz; i++){
                        Node nd = mp.get(i);
                        if (2*i < sz) nd.left = mp.get(2*i + 1);
                        if (2*i + 1 < sz) nd.right = mp.get(2*i + 2);
                    }
        
                    Queue<Integer> visit = new LinkedList<Integer>();
                    visit.add(0); // id = 0;
        
                    int j = 0;
                    int id = -1;
                    while (!visit.isEmpty()){
                        id = visit.poll();
                        if (str.charAt(j) == '1'){
                            mp.get(id).exists = true;
                            visit.add(2*id + 1);
                            visit.add(2*id + 2);
                        }else{
                            mp.get(id).exists = true;
                        }
                        j++;
                    }
        
                    System.out.println("NODES:");
                    for (int i=0; i<sz; i++){
                        if (mp.get(i).exists){
                            System.out.println(i);
                        }
                    }
        
                    System.out.println();
                    System.out.println("EDGES:");
                    for (int i=0; i<sz; i++){
                        if (mp.get(i).exists){
                            if (mp.get(2 * i + 1).exists){
                                System.out.println(i + " --> " + (2*i+1));
                            }
                            if (mp.get(2 * i + 2).exists){
                                System.out.println(i + " --> " + (2*i+2));
                            }
                        }
                    }
        
                }
        
            }
        

        这里是相同的解决方案简化版。
        没有树或地图,只有一个布尔数组。如果某个节点
        k 有孩子,这些孩子是 2*k+1 和 2*k+2。
        在打印边缘的最后一个循环中,也可以
        构造一棵实际的二叉树。

            import java.util.LinkedList;
            import java.util.Queue;
        
            public class Test32 {
        
                public static void main(String[] args) {
        
                    String str = "110101000";
                    int sz = (int)Math.pow(2, str.length() + 1);
                    boolean exists[] = new boolean[sz];
        
                    Queue<Integer> visit = new LinkedList<Integer>();
                    visit.add(0); // id = 0;
                    if (str.charAt(0) == '1'){
                        exists[0] = true;
                    }
        
                    int j = 0;
                    int id = -1;
                    while (!visit.isEmpty()){
                        id = visit.poll();
                        if (str.charAt(j) == '1'){
                            exists[id] = true;
                            visit.add(2*id + 1);
                            visit.add(2*id + 2);
                        }else{
                            exists[id] = true;
                        }
                        j++;
                    }
        
                    // System.out.println("");
                    System.out.println("NODES:");
                    for (int i=0; i<sz; i++){
                        if (exists[i]){
                            System.out.println(i);
                        }
                    }
        
                    System.out.println("");
                    System.out.println("EDGES:");
                    for (int i=0; i<sz; i++){
                        if (exists[i]){
                            if (exists[2*i+1]){
                                System.out.println(i + " --> " + (2*i+1));
                            }
                            if (exists[2*i+2]){
                                System.out.println(i + " --> " + (2*i+2));
                            }
                        }
                    }
        
                }
        
            }
        

        【讨论】:

          【解决方案6】:

          我认为概念上更简单。

          import java.util.LinkedList;
          import java.util.Queue;
          
          class WeirdBinaryTree
          {
          static class Node
          {
              private Node right;
              private Node left;
              private int weirdValue;
          
              public void setWeirdValue(int value)
              {
                  weirdValue=value;
              }
          }
          
          private static Node makeTree(String str)throws Exception
          {
              char[] array=str.toCharArray();
              Node root=new Node();
              Queue<Node> list=new LinkedList();
              list.add(root);
              int i=0;
              Queue<Node> nextList=new LinkedList<Node>();
              while(!list.isEmpty())
              {
                  if(array[i++]=='1')
                  {                
                          Node temp=list.poll();
                          temp.left=new Node();
                          temp.right=new Node();
                          temp.setWeirdValue(1);
                          nextList.add(temp.left);
                          nextList.add(temp.right);       
                  }
                  else
                  {
                      list.poll();
                  }
                  if(list.isEmpty())
                  {
                      list=nextList;
                      nextList=new LinkedList<Node>();
                  }
              }
              return root;
          }
          
          private static void postTraversal(Node localRoot)
          {
              if(localRoot!=null)
              {
                  postTraversal(localRoot.left);
                  postTraversal(localRoot.right);
                  System.out.print(localRoot.weirdValue);
              }
          }
          
          public static void main(String[] args)throws Exception 
          {
              postTraversal(makeTree("111001000"));
          }
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2016-07-11
            • 1970-01-01
            • 2017-08-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多