5

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

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

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

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

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

4

6 回答 6

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));
    }
}
于 2013-12-23T13:41:47.933 回答
2

以您的级别顺序遍历为例 - 111001000 树将如下所示

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

逻辑如下。

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

2) 转到下一位(B 为 1),因为它的值也是 1,它也有 2 个孩子,然后下一位(C 为 1)也有 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 就很容易了。

于 2013-12-23T13:37:20.163 回答
1

如果允许,我会在这里使用二进制堆作为助手。在使用标准表实现的二进制堆中,给定元素的索引,我们可以轻松计算其父元素的索引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)。

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

于 2013-12-23T13:33:39.840 回答
0

首先,我假设你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;
}
}
于 2013-12-23T13:24:08.110 回答
0

这是一个非常简单的解决方案。
虽然就内存而言并不是真正的最佳选择 ,因为我首先构建了一个完整/完整的树
,然后我标记了哪些节点实际存在于我们的树中。所以这
可以优化一点,我猜。

    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));
                    }
                }
            }

        }

    }
于 2013-12-23T13:59:49.510 回答
0

我认为在概念上更简单。

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"));
}
}
于 2013-12-30T15:34:00.017 回答