簡體   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