【问题标题】:Pre-order to post-order traversal前序到后序遍历
【发布时间】:2019-10-03 18:57:48
【问题描述】:

如果二叉搜索树的前序遍历是6、2、1、4、3、7、10、9、11,那么如何得到后序遍历?

【问题讨论】:

  • 您找不到唯一的答案。看:stackoverflow.com/questions/1219831/… 进一步讨论。
  • @ Ondrej Tucny - 不,但我正在准备数据结构考试,我画了 2 棵不同的树,它们的后序相同,所以我有点困惑
  • BST 满了吗?树中有 2^n 个节点吗?
  • @Gunner:对于二叉 search 树,它是唯一的,假设按顺序遍历是 1,2,...,(虽然我同意,有一些有歧义)。

标签: algorithm data-structures tree-traversal binary-search-tree


【解决方案1】:

给定树的前序遍历,它的构造方法是:输出,向左遍历,向右遍历。

由于后序遍历来自于BST,因此可以通过对数字进行排序,从后序遍历中推导出中序遍历(左遍历、输出、右遍历)。在您的示例中,按顺序遍历是 1、2、3、4、6、7、9、10、11。

通过两次遍历,我们可以构建原始树。让我们为此使用一个更简单的示例:

  • 预购:2、1、4、3
  • 按顺序:1、2、3、4

前序遍历给我们树的根为 2。中序遍历告诉我们 1 落入左子树,3、4 落入右子树。左子树的结构很简单,因为它包含一个元素。右子树的前序遍历是通过从原始的前序遍历中取该子树中元素的顺序来推导出的:4, 3。由此我们知道右子树的根是 4 和从有序遍历 (3, 4) 我们知道 3 落入左子树。我们的最终树如下所示:

  2
 / \
1   4
   /
  3

有了树形结构,我们可以通过遍历树得到后序遍历:向左遍历,向右遍历,输出。对于本例,后序遍历为 1、3、4、2。

概括算法:

  1. 前序遍历中的第一个元素是树的根。小于根的元素形成左子树。大于根的元素形成右子树。
  2. 使用步骤 1 查找左右子树的结构,其中包含我们计算出的元素在该子树中的前序遍历,这些元素按照它们在原始前序中出现的顺序排列遍历。
  3. 按后序遍历生成的树,以获得与给定前序遍历关联的后序遍历。

使用上述算法,问题中与前序遍历相关的后序遍历为:1、3、4、2、9、11、10、7、6。到达那里留作练习.

【讨论】:

  • 他专门询问二叉搜索树,因此当前节点的值与其左子树和右子树之间有明确的顺序。我在这里没有看到任何歧义。
  • @Ondrej Doh!完全不知道他正在使用 BST。将编辑它。
【解决方案2】:

预排序 = 按当前节点、左子树、右子树的顺序输出二叉树的值。

后序 = 按左子树、右子树、当前节点的顺序输出二叉树的值。

在二叉搜索树中,左子树中所有节点的值都小于当前节点的值;和右子树一样。因此,如果您知道二叉搜索树的前序转储的开始(即其根节点的值),您可以轻松地将整个转储分解为根节点值、左子树节点的值以及右子树的节点。

为了以后序输出树,应用递归和输出重新排序。这个任务留给读者。

【讨论】:

  • “二叉树”“二叉搜索树”问题在这里发挥了重要作用。
  • you can easily decompose the whole dump into the root node value. 没错。阅读所有我在想的复杂答案,“这真的很容易吗?”是的,是的。
【解决方案3】:

基于 Ondrej Tucny 的回答。仅适用于 BST
示例:

     20  
    /  \  
   10  30  
   /\    \  
  6  15   35  

预购 = 20 10 6 15 30 35
帖子 = 6 15 10 35 30 20

对于 BST,先序遍历;数组的第一个元素是 20。这是我们树的根。数组中小于 20 的所有数字形成其左子树,大于 20 的数字形成右子树。

//N = number of nodes in BST (size of traversal array)
int post[N] = {0}; 
int i =0;

void PretoPost(int pre[],int l,int r){
  if(l==r){post[i++] = pre[l]; return;}
  //pre[l] is root
  //Divide array in lesser numbers and greater numbers and then call this function on them recursively  
  for(int j=l+1;j<=r;j++) 
      if(pre[j]>pre[l])
          break;
  PretoPost(a,l+1,j-1); // add left node
  PretoPost(a,j,r); //add right node
  //root should go in the end
  post[i++] = pre[l]; 
  return;
 }

如有错误请指正。

【讨论】:

  • 正确,但平方时间复杂度使其效率低下。
【解决方案4】:

您将获得预购遍历结果。然后把这些值放到一个合适的二叉搜索树中,然后对得到的 BST 进行后序遍历算法。

【讨论】:

    【解决方案5】:

    这是python中前序到后序遍历的代码。 我正在构建一棵树,以便您可以找到任何类型的遍历

    def postorder(root):
        if root==None:
            return
        postorder(root.left)
        print(root.data,end=" ")
        postorder(root.right)
    
    def preordertoposorder(a,n):
        root=Node(a[0])
        top=Node(0)
        temp=Node(0)
        temp=None
        stack=[]
        stack.append(root)
        for i in range(1,len(a)):
            while len(stack)!=0 and a[i]>stack[-1].data:
                temp=stack.pop()
            if temp!=None:
                temp.right=Node(a[i])
                stack.append(temp.right)
            else:
                stack[-1].left=Node(a[i])
                stack.append(stack[-1].left)
        return root
    class Node:
        def __init__(self,data):
            self.data=data
            self.left=None
            self.right=None  
    a=[40,30,35,80,100]
    n=5
    root=preordertoposorder(a,n)
    postorder(root)
    # print(root.data)
    # print(root.left.data)
    # print(root.right.data)
    # print(root.left.right.data)
    # print(root.right.right.data)
    

    【讨论】:

      【解决方案6】:

      我知道这是旧的,但有更好的解决方案。

      我们不必重构 BST 来从预购中获取后购。

      这是一个简单的递归执行的python代码:

      import itertools
      
      def postorder(preorder):
          if not preorder:
              return []
          else:
              root = preorder[0]
              left = list(itertools.takewhile(lambda x: x < root, preorder[1:]))
              right = preorder[len(left) + 1:]
              return postorder(left) + postorder(right) + [root]
      
      if __name__ == '__main__':
          preorder = [20, 10, 6, 15, 30, 35]
          print(postorder(preorder))
      

      输出:

       [6, 15, 10, 35, 30, 20]
      

      解释

      我们知道我们已预订。这意味着根位于 BST 中值列表的索引 0。我们知道跟在根之后的元素是:

      • 第一:小于root的元素,属于根的左子树
      • 第二个:大于root的元素,属于根的右子树

      然后我们只是递归地调用两个子树上的函数(它们仍然在前序中),然后链接left + right + root(这是后序)。

      【讨论】:

        【解决方案7】:

        如果您已获得预购,并且您想将其转换为后购。那么你应该记住,在 BST 中,顺序总是按升序给出数字。因此,你既有 Inorder 又有构造树的前序。

        预购:6, 2, 1, 4, 3, 7, 10, 9, 11

        排序:1, 2, 3, 4, 6, 7, 9, 10, 11

        及其后序:1 3 4 2 9 11 10 7 6

        【讨论】:

          【解决方案8】:

          这里以数组形式给出二叉搜索树的前序遍历。 所以前序数组的第一个元素将是BST的根。我们将找到BST的左边部分和BST的右边部分。前序数组中所有小于根的元素将是左节点,并且所有前序中的元素-order 数组大于根将是右节点。

          #include <bits/stdc++.h>
          using namespace std;
          int arr[1002];
          int no_ans = 0;
          int n = 1000;
          int ans[1002] ;
          int k = 0;
          
          int find_ind(int l,int r,int x){
              int index = -1; 
              for(int i = l;i<=r;i++){
                  if(x<arr[i]){
                      index = i;
                      break;
                  }
              }
              if(index == -1)return index;
              for(int i =l+1;i<index;i++){
                  if(arr[i] > x){
                      no_ans = 1;
                      return index;
                  }
              }
              for(int i = index;i<=r;i++){
                  if(arr[i]<x){
                      no_ans = 1;
                      return index;
                  }
              }
              return index;
          
          }
          
          void postorder(int l ,int r){
          
              if(l < 0 || r >= n || l >r ) return;
              ans[k++] = arr[l];
              if(l==r) return;
              int index = find_ind(l+1,r,arr[l]);
              if(no_ans){
                  return;
              }
              if(index!=-1){
                  postorder(index,r);
                  postorder(l+1,index-1);
              }
              else{
                  postorder(l+1,r);
              }
          }
          
          int main(void){
          
              int t;
              scanf("%d",&t);
              while(t--){
                  no_ans = 0;
                  int n ;
                  scanf("%d",&n);
          
                  for(int i = 0;i<n;i++){
                      cin>>arr[i];
                  }
                  postorder(0,n-1);
                  if(no_ans){
                      cout<<"NO"<<endl;
                  }
                  else{
          
                      for(int i =n-1;i>=0;i--){
                          cout<<ans[i]<<" ";
                      }
                      cout<<endl;
                  }
              }
          
              return 0;
          } 
          

          【讨论】:

            【解决方案9】:

            据我们所知,preOrder 遵循父、左、右系列。

            为了构建树,我们需要遵循几个基本步骤-:

            您的问题包括系列 6、2、1、4、3、7、10、9、11

            积分-:

            1. 系列的第一个数字将是根(父),即 6

            2.找到大于 6 的数字,所以在这个系列中 7 是这个系列中的第一个更大的数字,所以右节点将从这里开始,左边到这个数字(7)是你的左子树。

                                  6
                                /   \
                               2     7
                             /  \     \
                            1    4     10
                                 /     / \
                                 3     9  11
            

            3.同样遵循BST的基本规则,即left,root,right

            后序序列为 L、R、N,即 1、3、4、2、9、11、10、7、6

            【讨论】:

              【解决方案10】:

              这是完整的代码)

              class Tree:
                  def __init__(self, data = None):
                      self.left = None
                      self.right = None
                      self.data = data
              
                  def add(self, data):
                      if self.data is None:
                          self.data = data
                      else:
                          if data < self.data:
                              if self.left is None:
                                  self.left = Tree(data)
                              else:
                                  self.left.add(data)
                          elif data > self.data:
                              if self.right is None:
                                  self.right = Tree(data)
                              else:
                                  self.right.add(data)
                  def inOrder(self):
                      if self.data:
                          if self.left is not None:
                              self.left.inOrder()
                          print(self.data)
                          if self.right is not None:
                              self.right.inOrder()
              
                  def postOrder(self):
                      if self.data:
                          if self.left is not None:
                              self.left.postOrder()
                          if self.right is not None:
                              self.right.postOrder()
                          print(self.data)
              
                  def preOrder(self):
                      if self.data:
                          print(self.data)
                          if self.left is not None:
                              self.left.preOrder()
                          if self.right is not None:
                              self.right.preOrder()
              arr = [6, 2, 1, 4, 3, 7, 10, 9, 11]
              root = Tree()
              for i in range(len(arr)):
                  root.add(arr[i])
              print(root.inOrder())
              

              【讨论】:

              • 请在您的代码周围添加一些解释。这将对未来的用户有所帮助。
              【解决方案11】:

              由于它是二叉搜索树,所以中序遍历总是排序后的元素。 (左

              所以,你可以很容易地先写出它的中序遍历结果,即:1,2,3,4,6,7,9,10,11

              预购:6、2、1、4、3、7、10、9、11

              按顺序:左、根、右 预购:根,左,右 后序:左、右、根

              现在,我们从预购中得到,root 是 6。

              现在,使用有序和预购结果: 第 1 步:

                           6
                          / \
                         /   \
                        /     \
                       /       \
                 {1,2,3,4}  {7,9,10,11}
              

              第 2 步:下一个根是,使用中序遍历,2:

                           6
                          / \
                         /   \
                        /     \
                       /       \
                      2  {7,9,10,11}
                     / \
                    /   \
                   /     \
                  1    {3,4}
              

              第 3 步:同样,下一个根是 4:

                           6
                          / \
                         /   \
                        /     \
                       /       \
                      2  {7,9,10,11}
                     / \
                    /   \
                   /     \
                  1       4
                         /
                        3
              

              第 4 步:下一个根是 3,但没有其他元素可以适合“3”的子树。现在考虑下一个根为 7,

                           6
                          / \
                         /   \
                        /     \
                       /       \
                      2         7
                     / \         \
                    /   \       {9,10,11}
                   /     \
                  1       4
                         /
                        3
              

              第 5 步:下一个根是 10:

                           6
                          / \
                         /   \
                        /     \
                       /       \
                      2         7
                     / \         \
                    /   \         10
                   /     \       /  \
                  1       4     9   11
                         /
                        3
              

              这样,你可以构造一棵树,最后找到它的后序遍历,即:1、3、4、2、9、11、10、7、6

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2011-03-01
                相关资源
                最近更新 更多