繁体   English   中英

如何仅从级别顺序遍历字符串构造二叉树

[英]How to construct a binary tree from just the level order traversal string

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

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

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

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

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

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

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

逻辑如下。

1)如果它的1(根)是第一位,那么接下来的2 ^ 1是该父级的子级的值。 因此,第二和第三位是A(根)的子代。

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

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

4)再次遍历或尝试重新设置-从第4、5、6和7位开始,只有一位是1,因此下2 ^ 1位将进入下一级,而这些位将是F的子级。

树制作完成后,轻松转换为PostFix。

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

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

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

因此,基本上,我们遍历表格。 我们将每个字段(root除外,在0处)初始化为-1,这意味着那里没有节点。 然后,我们检查该字段的父级是否为1。如果是,则将输入流中的下一个元素放在堆中当前索引(heapIndex)上。 如果当前字段的父级为0,则我们走得更远,因为这意味着我们的父级是叶子并且不应有任何子级。

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

就内存而言,此算法可能效率很低,但我希望它很容易理解。

首先,我假设您的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;
}
}

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

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

        }

    }

我认为从概念上讲更简单。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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