简体   繁体   English

如何从preorder和inorder遍历构建二叉树

[英]how to build a binary tree from preorder and inorder traversals

Im doing an assignment on building a binary tree from the preorder and inorder traversals (a char in each Node) and im trying to wrap my brain around how to build the actual tree. 我正在做一个关于从预订和顺序遍历(每个节点中的一个字符串)构建二叉树的任务,并试图围绕如何构建实际树包裹我的大脑。

Here is my thought process on how to accomplish this: 以下是关于如何实现此目标的思考过程:

  1. store the first entry in the preorder as the root node 将预订中的第一个条目存储为根节点
  2. search the inorder for that entry. 搜索该条目的顺序。
  3. take the chars to the left of the root node and save them as a char array. 将字符放在根节点的左侧,并将它们保存为char数组。
  4. take the chars to the right of the root node and save them as a char array. 将字符放在根节点的右侧,并将它们保存为char数组。
  5. make a new tree, with the root as the parent and its 2 children being the left and right char arrays. 创建一个新树,以root作为父,其中2个子元素为左右char数组。
  6. keep going recursively until the preorder length is 0. 继续递归,直到预订长度为0。

I have steps 1-4 taken care of, but im not too sure how to properly build my tree, and was wondering if anyone had any pointers. 我已经完成了步骤1-4,但是我不太确定如何正确构建我的树,并且想知道是否有人有任何指针。 Thank you. 谢谢。

Do the recursion before building the new tree. 在构建新树之前执行递归。 So, your list would look like this: 所以,你的列表看起来像这样:

  1. If the arrays have length 1, just return a leaf node with this single item in it. 如果数组的长度为1,则只返回包含此单个项目的叶节点。 (This is the recursion foundation.) (O(1)) (这是递归基础。) (O(1))
  2. Store the first entry in the preorder array as the root node. 将第一个条目存储在预订单数组中作为根节点。 (O(1)) (O(1))
  3. Search the inorder array for that entry. 在inorder数组中搜索该条目。 (O(n)) (上))
  4. Take the chars to the left of the root node in the inorder array and save them as a char array. 将字符放在inorder数组中根节点的左侧,并将它们保存为char数组。 Take the same amount of characters from the preorder array (after the root). 从预订单数组中获取相同数量的字符(在根之后)。 (O(n), or O(1) when just throwing pointers/indexes around.) (O(n)或O(1)只是抛出指针/索引。)
  5. Take the chars to the right of the root node and save them as a char array. 将字符放在根节点的右侧,并将它们保存为char数组。 Take the same amount of characters from the preorder array (after the first part – that should be just the remainding part). 从预订单数组中获取相同数量的字符(在第一部分之后 - 应该只是剩余部分)。 (O(n), or O(1) when just throwing pointers/indexes around.) (O(n)或O(1)只是抛出指针/索引。)
  6. Recursively make a tree from both left char arrays. 从两个char数组递归地生成一个树。
  7. Recursively make a tree from both right char arrays. 从两个正确的char数组递归地生成一个树。
  8. Combine both trees with your root node. 将两个树与根节点组合在一起。 (O(1).) (O(1)。)

The non-recursive parts can be done in O(n) overall, and summing them up for each recursion level is also O(n) each. 非递归部分可以在O(n)中完成,并且对于每个递归级别对它们求和也是每个O(n)。 The total runtime thus depends on the number of recursion levels. 因此总运行时间取决于递归级别的数量。 If you have a approximately balanced tree, the depth is O(log n), thus we get to O(n · log n) at all. 如果你有一个近似平衡的树,深度是O(log n),因此我们得到O(n·log n)。 As the only necessarily slow part is the search of the root node in the inorder array, I guess we could optimize that even a bit more if we know more about the tree. 由于唯一缓慢的部分是在inorder数组中搜索根节点,我想如果我们对树有更多的了解,我们可以优化它。

In the worst case we have one recursion level for each node in the tree, coming to complexity O(n·n). 在最坏的情况下,我们在树中的每个节点都有一个递归级别,达到复杂度O(n·n)。

Example: Preorder ABCDEF, Inorder FEDCBA, Tree: 示例:预购ABCDEF,Inorder FEDCBA,树:

                                   +---+
                                   | A |
                                   ++--+
                                    |
                            +---+   |
                            | B +<--+
                            ++--+
                             |
                     +---+   |
                     | C +<--+
                     ++--+
                      |
              +---+   |
              | D +<--+
              ++--+
               |
       +---+   |
       | E +<--+
       ++--+
        |
+---+   |
| F +<--+
+---+

You can use the below code, I just wrote for the same problem. 你可以使用下面的代码,我刚刚写了同样的问题。 It works for me. 这个对我有用。

public class TreeFromInorderAndPreOrder {

public static List<Integer> inOrder = new ArrayList<Integer>();
public static List<Integer> preOrder = new ArrayList<Integer>();

public static void main(String[] args) {

    Node root = new Node();
    root.createRoot(5);
    for(int i = 0 ; i < 9 ; i++){
        if(i != 5){
            root.insert(i);
        }
    }

    inOrder(root);
    preOrder(root);
    for(Integer temp : inOrder){
        System.out.print(temp +  " ");
    }

    System.out.println();
    for(Integer temp : preOrder){
        System.out.print(temp + " ");
    }

    Node node1 = null;
    node1 = reConstructTree(root, (ArrayList<Integer>) inOrder, true);

    System.out.println();
    inOrder(node1);
    for(Integer temp : inOrder){
        System.out.print(temp +  " ");
    }

    System.out.println();

    for(Integer temp : preOrder){
        System.out.print(temp + " ");
    }

}

public static void inOrder(Node node){

    if(node!= null){
        inOrder(node.leftchild);
        inOrder.add(node.key);
        inOrder(node.rightChild);
    }

}

public static void preOrder(Node node){

    if(node != null){
        preOrder.add(node.key);
        preOrder(node.leftchild);
        preOrder(node.rightChild);
    }

}

public static Node reConstructTree(Node root, ArrayList<Integer> inOrder, 
    boolean  isLeft){

    if(preOrder.size() != 0 && inOrder.size() != 0){
        return null;
    }

    Node node = new Node();
    node.createRoot(preOrder.get(0));
    if(root != null && isLeft){
        root.leftchild = node;          
    }else if(root != null && !isLeft){
        root.rightChild = node;
    }
    int indx = inOrder.get(preOrder.get(0));
    preOrder.remove(0);
    List<Integer> leftInorder = getSublist(0, indx);
    reConstructTree(node, (ArrayList<Integer>) leftInorder, true);
    List<Integer> rightInorder = getSublist(indx+1, inOrder.size());
    reConstructTree(node, (ArrayList<Integer>)rightInorder, false);
    return node;

}

public static ArrayList<Integer> getSublist(int start, int end){
    ArrayList<Integer> list = new ArrayList<Integer>();
    for(int i = start ; i < end ; i++){
        list.add(inOrder.get(i));
    }

    return list;
}
}

I have written a sample program using divide and conquer approach using recursion in java 我已经使用java中的递归使用分而治之的方法编写了一个示例程序

import java.util.LinkedList;
import java.util.Queue;

public class BinaryTreeNode {

private char data;
public char getData() {
    return data;
}
public void setData(char data) {
    this.data = data;
}
public BinaryTreeNode getLeft() {
    return left;
}
public void setLeft(BinaryTreeNode left) {
    this.left = left;
}
public BinaryTreeNode getRight() {
    return right;
}
public void setRight(BinaryTreeNode right) {
    this.right = right;
}
private BinaryTreeNode left;
private BinaryTreeNode right;

public static void levelTravesal(BinaryTreeNode node)
{
    Queue queue = new LinkedList();

    if(node == null)
        return;
    queue.offer(node);
    queue.offer(null);
    int level =0;
    while(!queue.isEmpty())
    {
        BinaryTreeNode temp = (BinaryTreeNode) queue.poll();

        if(temp == null)
        {
            System.out.println("Level: "+level);
            if(!queue.isEmpty())
                queue.offer(null);
            level++;
        }else {

        System.out.println(temp.data);

        if(temp.getLeft()!=null)
            queue.offer(temp.getLeft());

        if(temp.getRight()!=null)
            queue.offer(temp.getRight());
        }

    }
}

static int preIndex = 0;

public static void main(String[] args) {

    if(args.length < 2)
    {
        System.out.println("Usage: preorder inorder");
        return;
    }

    char[] preOrderSequence = args[0].toCharArray();
    char[] inOrderSequence = args[1].toCharArray();

    //char[] preOrderSequence = {'A','B','D','E','C','F'};
    //char[] inOrderSequence = "DBEAFC".toCharArray();

    if(preOrderSequence.length != inOrderSequence.length)
    {
        System.out.println("Pre-order and in-order sequences must be of same length");
        return;
    }

    BinaryTreeNode root = buildBinaryTree(preOrderSequence, inOrderSequence, 0, preOrderSequence.length-1);

    System.out.println();
    levelTravesal(root);


}

static BinaryTreeNode buildBinaryTree(char[] preOrder, char[] inOrder, int start, int end)
{
    if(start > end)
        return null;
    BinaryTreeNode rootNode = new BinaryTreeNode();
    rootNode.setData(preOrder[preIndex]);
    preIndex++;
    //System.out.println(rootNode.getData());
    if(start == end)
        return rootNode;
    int dataIndex = search(inOrder, start, end, rootNode.getData());
    if(dataIndex == -1)
        return null;
    //System.out.println("Left Bounds: "+start+" "+(dataIndex-1));
    rootNode.setLeft(buildBinaryTree(preOrder, inOrder, start, dataIndex - 1));
    //System.out.println("Right Bounds: "+(dataIndex+1)+" "+end);
    rootNode.setRight(buildBinaryTree(preOrder, inOrder, dataIndex+1, end));
    return rootNode;
}


static int search(char[] inOrder,int start,int end,char data)
{
    for(int i=start;i<=end;i++)
    {
        if(inOrder[i] == data)
            return i;
    }
    return -1;

}

}

Here is a mathematical approach to achieve the thing in a very simplistic way : 这是一种以非常简单的方式实现事物的数学方法:

Language used : Java 使用的语言:Java

` `
/* Algorithm for constructing binary tree from given Inorder and Preorder traversals. / *从给定的Inorder和Preorder遍历构造二叉树的算法。 Following is the terminology used : 以下是使用的术语:

i : represents the inorder array supplied i:表示提供的inorder数组

p : represents the preorder array supplied p:表示提供的预订单数组

beg1 : starting index of inorder array beg1:inorder数组的起始索引

beg2 : starting index of preorder array beg2:预编程数组的起始索引

end1 : ending index of inorder array end1:inorder数组的结束索引

end2 : ending index of preorder array end2:预订单数组的结束索引

*/ * /

public static void constructTree(Node root, int[] i, int[] p, int beg1, int end1, int beg2, int end2) public static void constructTree(Node root,int [] i,int [] p,int beg1,int end1,int beg2,int end2)

{ {

if(beg1==end1 && beg2 == end2)
{
    root.data = i[beg1];
}
else if(beg1<=end1 && beg2<=end2)
{
    root.data = p[beg2];
    int mid = search(i, (int) root.data);
    root.left=new Node();
    root.right=new Node();
    constructTree(root.left, i, p, beg1, mid-1, beg2+1, beg2+mid-beg1);
    System.out.println("Printing root left : " + root.left.data);
    constructTree(root.right, i, p, mid+1, end1, beg2+1+mid-beg1, end2);
    System.out.println("Printing root left : " + root.right.data);
}

} }

` `

You need invoke the function by following code : 您需要通过以下代码调用该函数:

int[] i ={4,8,7,9,2,5,1,6,19,3,18,10}; //Inorder
int[] p ={1,2,4,7,8,9,5,3,6,19,10,18}; //Preorder
Node root1=new Node();
constructTree(root1, i, p, 0, i.length-1, 0, p.length-1);

In case you need a more elaborate explanation of code please mention it in the comments. 如果您需要更详细的代码说明,请在评论中提及。 I would be happy to help :). 我很乐意帮助:)。

See my answer to this question . 见我回答这个问题 You build the tree by adding nodes in pre-order sequence, but by using the inorder position as comparator. 您可以通过在预订序列中添加节点来构建树,但是使用inorder位置作为比较器。

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

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