【问题标题】:how to build a binary tree from preorder and inorder traversals如何从前序遍历和中序遍历构建二叉树
【发布时间】:2011-07-09 22:37:40
【问题描述】:

我正在做一个关于从前序和中序遍历(每个节点中的一个字符)构建二叉树的任务,并且我试图围绕如何构建实际的树来思考。

以下是我对如何实现此目的的思考过程:

  1. 将预排序中的第一个条目存储为根节点
  2. 在订单中搜索该条目。
  3. 将根节点左侧的字符保存为字符数组。
  4. 将根节点右侧的字符保存为字符数组。
  5. 创建一棵新树,以根为父级,其 2 个子级为左右 char 数组。
  6. 继续递归直到预购长度为 0。

我已经完成了步骤 1-4,但我不太确定如何正确构建我的树,并且想知道是否有人有任何指示。谢谢。

【问题讨论】:

    标签: java binary-tree


    【解决方案1】:

    这是一种以非常简单的方式实现这一目标的数学方法:

    使用语言:Java

    `
    /* 从给定的中序和前序遍历构造二叉树的算法。 以下是使用的术语:

    i : 表示提供的中序数组

    p : 表示提供的预购数组

    beg1 : 中序数组的起始索引

    beg2 : 前序数组的起始索引

    end1 : 中序数组的结束索引

    end2 : 前序数组的结束索引

    */

    公共静态无效构造树(节点根,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);
    }
    

    }

    `

    您需要通过以下代码调用该函数:

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

    如果您需要更详细的代码解释,请在 cmets 中提及。我很乐意提供帮助:)。

    【讨论】:

      【解决方案2】:

      在构建新树之前进行递归。因此,您的列表将如下所示:

      1. 如果数组的长度为 1,则只返回一个包含该单项的叶节点。 (这是递归的基础。)(O(1))
      2. 将预排序数组中的第一个条目存储为根节点。 (O(1))
      3. 在中序数组中搜索该条目。 (O(n))
      4. 将中序数组中根节点左侧的字符保存为字符数组。从预排序数组(根之后)中获取相同数量的字符。 (O(n) 或 O(1),当只是抛出指针/索引时。)
      5. 将根节点右侧的字符保存为字符数组。从预排序数组中获取相同数量的字符(在第一部分之后——应该只是剩下的部分)。 (O(n) 或 O(1),当只是抛出指针/索引时。)
      6. 从两个左 char 数组递归地创建一棵树。
      7. 从两个右字符数组递归地创建一棵树。
      8. 将两棵树与您的根节点合并。 (O(1).)

      非递归部分总体上可以在 O(n) 内完成,每个递归级别的总和也是 O(n)。因此,总运行时间取决于递归级别的数量。如果你有一个近似平衡的树,深度是 O(log n),因此我们得到 O(n · log n)。由于唯一必然缓慢的部分是在中序数组中搜索根节点,我想如果我们对树有更多了解,我们可以进一步优化它。

      在最坏的情况下,树中的每个节点都有一个递归级别,复杂度为 O(n·n)。

      示例:预购 ABCDEF、中序 FEDCBA、树:

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

      【讨论】:

      • 这是一个很酷的方法。但是您必须同时划分有序序列和预购序列,不是吗?
      • 是的,看起来是这样。我认为这很容易,因为您可以从 inorder 分区中获取预购的分区大小。
      • 你是对的,这很容易。只需要确保分区正确完成。你的方法是在纸上做的最简单的方法。
      • @Paŭlo Ebermann - 运行时间是否优于 O(n*n) ? n=树中的节点总数
      • @BuckCherry 我没有证据,我目前也没有心情实际创建一个。我猜最好的情况(平衡树)类似于O(n· log n)。最坏的情况可能是O(n²)(就像一个链表,即根节点总是在搜索中的最后一个)。
      【解决方案3】:

      我在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;
      
      }
      
      }
      

      【讨论】:

        【解决方案4】:

        你可以使用下面的代码,我只是为同样的问题写的。它对我有用。

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

        【讨论】:

          【解决方案5】:

          看到我的answer 到这个question。您可以通过按前序顺序添加节点来构建树,但使用中序位置作为比较器。

          【讨论】:

          • 虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接答案可能会失效。 - From Review
          • @AhmedAshour:我不同意……这不是仅链接的答案。 Andre 给出了他的解决方案的 [简短] 描述,然后是一个代码示例的链接。仅仅因为答案很短并且有链接,并不会自动使其成为仅链接的答案。见:meta.stackoverflow.com/questions/287563/…
          • @AhmedAshour,该链接指向 SO 上的页面。大多数“仅链接”的问题是潜在的死链接。如果该链接失效,则该页面也可能失效。
          猜你喜欢
          • 2021-09-03
          • 1970-01-01
          • 2021-03-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-01-09
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多