二阶树构造从预订

时间:2011-03-16 02:54:38

标签: algorithm binary-tree

这是亚马逊的采访问题。任何人都可以给出算法吗?

有一个具有以下属性的二叉树:

  • 其所有内部节点的值均为'N',所有树叶的值均为'L'
  • 每个节点都有两个孩子或没有孩子。

根据预先排序,构造树并返回根节点。

5 个答案:

答案 0 :(得分:3)

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

我们用提供的输入调用我们的函数,并检查它得到的第一个字符。如果它是叶节点,它只返回一个叶子。如果它是一个内部节点,它只是为左右子树调用自己,并返回使用节点作为root形成的树,并将左右子树作为其左右子节点。

代码如下(在Python中)。注意,我使用tuple来表示节点,因此树是tuple tuples

#! /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+")";
                }
        }
}

答案 1 :(得分:0)

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

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

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

答案 2 :(得分:0)

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

  1. NN:第二个N是第一个N的左子,但是我们不知道前N个合适的孩子是什么
  2. NL ?:第二个N是第一个N的左子,第一个N的右子是?
  3. L?:?是STACK top
  4. 的合适孩子

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

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

答案 3 :(得分:0)

这是java程序::

import java.util。*;

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

  }

}

答案 4 :(得分:0)

construct函数执行实际的树构建。该代码段是您上面提到的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. 索引已声明为引用变量,因此返回到父节点后,该函数将根据整个索引的最新值而不是索引的值开始构建树最初执行调用时函数所拥有的。

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

希望有帮助。