【问题标题】:binary tree construction from preorder从前序构造二叉树
【发布时间】:2011-03-16 02:54:37
【问题描述】:

这是一个亚马逊面试问题。谁能给出一个算法来做到这一点?

有一棵二叉树具有以下性质:

  • 其所有内部节点的值为'N',所有叶子的值为'L'
  • 每个节点要么有两个子节点,要么没有子节点。

给定它的前序,构造树并返回根节点。

【问题讨论】:

  • 您确实应该具备数据结构方面的知识,但预购只是Root,LeftNode,RightNode。
  • @TrevorMA- 没错,但这不是被问到的。这个想法是如何在给定遍历的情况下重建树,这需要您了解的不仅仅是预序是什么。

标签: algorithm binary-tree


【解决方案1】:

由于保证每个内部节点恰好有 2 个子节点,我们可以简单地使用它递归地构建树。​​

我们使用提供的输入调用我们的函数,它会检查它得到的第一个字符。如果它是一个叶子节点,它只返回一个叶子。如果是内部节点,只调用左右子树,返回以该节点为根,左右子树为左右子节点形成的树。

代码如下(在 Python 中)。注意,我使用tuples 表示节点,所以树是tupletuples

#! /usr/bin/env python
from collections import deque

def build_tree(pre_order):
        root=pre_order.popleft()
        if root=='L':
                return root
        else:
                return (root,build_tree(pre_order),build_tree(pre_order))

if __name__=='__main__':
        print build_tree(deque("NNLLL"))

编辑:Java 代码

import java.util.*;
class Preorder{
        public static Node buildTree(List<Character> preorder){
                char token=preorder.remove(0);
                if (token=='L'){
                        return new Node(token,null,null);
                }
                else{
                        return new Node(token,buildTree(preorder),buildTree(preorder));

                }
        }
        public static void main(String args[]){
                List<Character> tokens=new LinkedList<Character>();
                String input="NNLLL";
                for(int i=0;i<input.length();i++) tokens.add(input.charAt(i));
                System.out.println(buildTree(tokens));
        }
}

class Node{
        char value;
        Node left,right;
        public Node(char value, Node left, Node right){
                this.value=value;
                this.left=left;
                this.right=right;
        }

        public String toString(){
                if (left==null && right==null){
                        return "("+value+")";
                }
                else{
                        return "("+value+", "+left+", "+right+")";
                }
        }
}

【讨论】:

  • 如果你能提供java或c的代码,那就太好了。提前谢谢。
  • @Nohsib:在 Java 中添加了代码。比 Python 长一点(Java 稍微冗长一些),但想法相同。
【解决方案2】:

我可以想到一个递归算法。

head = 新节点。 删除preorderString中的第一个字符
调用f(head, preorderString)

递归函数f(node, s)
- 从 s 中删除第一个字符,如果 L 则作为叶子附加到节点。
否则创建 nodeLeft,附加到节点,调用 f(nodeLeft, s)
- 从 s 中删除第一个字符,如果 L 则作为叶子附加到节点。
否则创建一个 nodeRight,附加到节点,调用 f(nodeRight, s)

【讨论】:

    【解决方案3】:

    我认为关键是要认识到相邻节点存在三种可能性:NN、NL?、L? (``?'' 表示 N 或 L)

    1. NN:第二个 N 是第一个 N 的左孩子,但我们不知道第一个 N 的右孩子是什么
    2. NL?:第二个 N 是第一个 N 的左孩子,第一个 N 的右孩子是?
    3. L?: ?是栈顶的右孩子

    使用 STACK 是因为当我们在预排序序列中读取一个节点时,我们不知道它的右孩子在哪里(我们知道它的左孩子在哪里,只要它有一个)。一个 STACK 存储这个节点,这样当它的右孩子出现时,我们可以弹出它并完成它的右链接。

    NODE * preorder2tree(void)
    {
        NODE * head = next_node();
        NODE * p = head;
        NODE * q;
    
        while (1) {
                q = next_node();
                if (!q)
                        break;
    
                /* possibilities of adjacent nodes:
                 * NN, NL?, L?
                 */
                if (p->val == 'N') {
                        p->L = q;
                        if (q->val == 'N') { /* NN */
                                push(p);
                                p = q;
                        } else {             /* NL? */
                                q = next_node();
                                p->R = q;
                                p = q;
                        }
                } else {                     /* L? */
                        p = pop();
                        p->R = q;
                        p = q;
                }
        }
        return head;
    }
    

    上面的代码使用一些简单的案例进行了测试。希望是正确的。

    【讨论】:

      【解决方案4】:

      这里是java程序::

      导入 java.util.*;

      类 preorder_given_NNNLL {

      static Stack<node> stk = new Stack<node>();
      static node root=null;
      
        static class node
        {
            char value;
            node left;
           node right;
            public node(char value)
            {
                    this.value=value;
                    this.left=null;
                    this.right=null;
            }
      
      
        }
      
        public static node stkoper()
        {
            node posr=null,posn=null,posl=null;
            posr=stk.pop();
            if(stk.empty())
            {
                stk.push(posr);
                return null;
            }
            else
                posl=stk.pop();
      
            if(stk.empty())
            {
                stk.push(posl);
                stk.push(posr);
                return null;
      
            }
            else
            {
                posn=stk.pop();
            }
      
      
            if( posn.value == 'N' && posl.value == 'L' && posr.value == 'L')
            {
      
                root = buildtree(posn, posl, posr);
      
                if(stk.empty())
                {
                    return root;
      
                }
                else
                {
                    stk.push(root);
      
      
                    root=stkoper();
                }
            }
            else
            {
                stk.push(posn);
                stk.push(posl);
                stk.push(posr);
            }
          return root;
      
      
        }
      
      
        public static node buildtree(node posn,node posl,node posr)
        {         
            posn.left=posl;
            posn.right=posr;
            posn.value='L';
            return posn;
      
        }
      
        public static void inorder(node root)
          {
              if(root!=null)
              {
                  inorder(root.left);
                  if((root.left == null) && (root.right == null))
                      System.out.println("L");
                  else
                      System.out.println("N");
                  inorder(root.right);
              }
      }
      
        public static void main(String args[]){
      
                String input="NNNLLLNLL";
                char[] pre = input.toCharArray();
               for (int i = 0; i < pre.length; i++) 
               {
                  node temp = new node(pre[i]);
                  stk.push(temp);
                  root=stkoper();
               }
      
               inorder(root);
      
        }
      

      }

      【讨论】:

        【解决方案5】:

        construct 函数执行实际的树构造。代码 sn-p 就是你上面提到的 GeeksforGeeks 问题的解决方案。

            struct Node*construct(int &index, Node*root, int pre[], int n, char preLN[])
        {   
            Node*nodeptr;
            if(index==n)
            {
                return NULL;
            }
            if(root==NULL)
            {
                nodeptr = newNode(pre[index]);
            }
            if(preLN[index]=='N')
            {   
                index = index+1;
                nodeptr->left = construct(index, nodeptr->left, pre,n,preLN);
                index = index+1;
                nodeptr->right = construct(index, nodeptr->right,pre,n,preLN);
                return nodeptr;
            }
            return nodeptr;
        }
        struct Node *constructTree(int n, int pre[], char preLN[])
        {   
            int index =0;
            Node*root = construct(index,NULL,pre,n,preLN);
            return root;
        }
        

        注意事项:

        1. Index 已被声明为引用变量,因此在返回父节点时,该函数开始从 索引的整体最新值而不是索引的值构造树函数在最初执行调用时所拥有的。

        2. 由于前序遍历遵循 Root、Left、Right 节点序列,因此左右子树的索引值不同。

        希望对你有帮助。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2021-09-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-03-28
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多