📌  相关文章
📜  使用 O(1) 空间在 O(N) 中的二叉树的后序遍历

📅  最后修改于: 2021-09-07 02:24:42             🧑  作者: Mango

先决条件:- Morris 中序遍历、树遍历(中序、前序和后序)
给定一个二叉树,任务是使用 O(N) 时间复杂度和常数空间按后序打印元素。

Input:   1 
       /   \
     2       3
    / \     / \
   4   5   6   7
  / \
 8   9
Output: 8 9 4 5 2 6 7 3 1

Input:   5 
       /   \
     7       3
    / \     / \
   4   11  13  9
  / \
 8   4
Output: 8 4 4 11 7 13 9 3 5

方法 1:使用莫里斯中序遍历

  1. 创建一个虚拟节点并将根作为它的左子节点。
  2. 用虚拟节点初始化电流。
  3. 虽然当前不是 NULL
    • 如果当前没有左孩子遍历右孩子,则current = current->right
    • 除此以外,
      1. 在左子树中找到最右边的孩子。
      2. 如果最右边的孩子的右孩子是 NULL
        • 使 current 作为最右边节点的右子节点。
        • 遍历左孩子,current = current->left
      3. 除此以外,
        • 将最右边的孩子的右指针设置为 NULL。
        • 从 current 的左孩子开始,与右孩子一起遍历直到最右边的孩子并反转指针。
        • 通过反转指针并打印元素,从最右边的子节点返回到当前的左子节点。
      4. 遍历右孩子,current = current->right

下图显示了左子树中最右边的孩子,指向它的中序后继。

下图突出显示了路径 1->2->5->9 以及按照上述算法处理和打印节点的方式。

下面是上述方法的实现:

C++
// C++ program to implement
// Post Order traversal
// of Binary Tree in O(N)
// time and O(1) space
#include 
using namespace std;
 
class node
{
    public:
    int data;
    node *left, *right;
};
 
// Helper function that allocates a
// new node with the given data and
// NULL left and right pointers.
node* newNode(int data)
{
    node* temp = new node();
    temp->data = data;
    temp->left = temp->right = NULL;
    return temp;
}
 
// Postorder traversal without recursion
// and without stack
void postOrderConstSpace(node* root)
{
    if (root == NULL)
            return;
 
        node* current = newNode(-1);
        node* pre = NULL;
        node* prev = NULL;
        node* succ = NULL;
        node* temp = NULL;
         
        current->left = root;
         
    while (current)
    {
         
        // If left child is null.
        // Move to right child.
        if (current->left == NULL)
        {
            current = current->right;
        }
        else
        {
            pre = current->left;
             
            // Inorder predecessor
            while (pre->right &&
                pre->right != current)
                pre = pre->right;
             
            // The connection between current and
            // predecessor is made
            if (pre->right == NULL)
            {
                 
                // Make current as the right
                // child of the right most node
                pre->right = current;
                 
                // Traverse the left child
                current = current->left;
            }
            else
            {
                pre->right = NULL;
                succ = current;
                current = current->left;
                prev = NULL;
                 
                // Traverse along the right
                // subtree to the
                // right-most child
                while (current != NULL)
                {
                    temp = current->right;
                    current->right = prev;
                    prev = current;
                    current = temp;
                }
                 
                // Traverse back
                // to current's left child
                // node
                while (prev != NULL)
                {
                    cout << prev->data << " ";
                    temp = prev->right;
                    prev->right = current;
                    current = prev;
                    prev = temp;
                }
 
                current = succ;
                current = current->right;
            }
        }
    }
}
 
// Driver code
int main()
{
   /* Constructed tree is as follows:-
                      1
                   /     \
                  2       3
                 / \     / \
                4   5   6   7
                   / \
                  8   9
      */
    node* root = NULL;
 
    root = newNode(1);
    root->left = newNode(2);
    root->right = newNode(3);
 
    root->left->left = newNode(4);
    root->left->right = newNode(5);
 
    root->right->left = newNode(6);
    root->right->right = newNode(7);
 
    root->left->right->left = newNode(8);
    root->left->right->right = newNode(9);
     
    postOrderConstSpace(root);
    return 0;
}
 
// This code is contributed by Saurav Chaudhary


Java
// Java program to implement
// Post Order traversal
// of Binary Tree in O(N)
// time and O(1) space
 
// Definition of the
// binary tree
class TreeNode {
    public int data;
    public TreeNode left;
    public TreeNode right;
    public TreeNode(int data)
    {
        this.data = data;
    }
 
    public String toString()
    {
        return data + " ";
    }
}
 
public class PostOrder {
 
    TreeNode root;
 
    // Function to find Post Order
    // Traversal Using Constant space
    void postOrderConstantspace(TreeNode
                                    root)
    {
        if (root == null)
            return;
 
        TreeNode current
            = new TreeNode(-1),
            pre = null;
        TreeNode prev = null,
                succ = null,
                temp = null;
        current.left = root;
 
        while (current != null) {
 
            // Go to the right child
            // if current does not
            // have a left child
 
            if (current.left == null) {
                current = current.right;
            }
 
            else {
 
                // Traverse left child
                pre = current.left;
 
                // Find the right most child
                // in the left subtree
                while (pre.right != null
                    && pre.right != current)
                    pre = pre.right;
 
                if (pre.right == null) {
 
                    // Make current as the right
                    // child of the right most node
                    pre.right = current;
 
                    // Traverse the left child
                    current = current.left;
                }
 
                else {
                    pre.right = null;
                    succ = current;
                    current = current.left;
                    prev = null;
 
                    // Traverse along the right
                    // subtree to the
                    // right-most child
 
                    while (current != null) {
                        temp = current.right;
                        current.right = prev;
                        prev = current;
                        current = temp;
                    }
 
                    // Traverse back from
                    // right most child to
                    // current's left child node
 
                    while (prev != null) {
 
                        System.out.print(prev);
                        temp = prev.right;
                        prev.right = current;
                        current = prev;
                        prev = temp;
                    }
 
                    current = succ;
                    current = current.right;
                }
            }
        }
    }
 
    // Driver Code
    public static void main(String[] args)
    {
        /* Constructed tree is as follows:-
                      1
                    /   \
                   2     3
                  / \    / \
                 4   5   6  7
                    / \
                    8  9
        */
        PostOrder tree = new PostOrder();
        tree.root = new TreeNode(1);
        tree.root.left = new TreeNode(2);
        tree.root.right = new TreeNode(3);
        tree.root.left.left = new TreeNode(4);
        tree.root.left.right
            = new TreeNode(5);
        tree.root.right.left
            = new TreeNode(6);
        tree.root.right.right
            = new TreeNode(7);
        tree.root.left.right.left
            = new TreeNode(8);
        tree.root.left.right.right
            = new TreeNode(9);
 
        tree.postOrderConstantspace(
            tree.root);
    }
}


Python3
# Python3 program to implement
# Post Order traversal
# of Binary Tree in O(N)
# time and O(1) space
class node:
     
    def __init__(self, data):
         
        self.data = data
        self.left = None
        self.right = None
 
# Helper function that allocates a
# new node with the given data and
# None left and right pointers.
def newNode(data):
 
    temp = node(data)
    return temp
 
# Postorder traversal without recursion
# and without stack
def postOrderConstSpace(root):
 
    if (root == None):
        return
 
    current = newNode(-1)
    pre = None
    prev = None
    succ = None
    temp = None
     
    current.left = root
         
    while (current):
         
        # If left child is None.
        # Move to right child.
        if (current.left == None):
            current = current.right
        else:
            pre = current.left
             
            # Inorder predecessor
            while (pre.right and
                   pre.right != current):
                pre = pre.right
             
            # The connection between current
            # and predecessor is made
            if (pre.right == None):
                 
                # Make current as the right
                # child of the right most node
                pre.right = current
                 
                # Traverse the left child
                current = current.left
             
            else:
             
                pre.right = None
                succ = current
                current = current.left
                prev = None
                 
                # Traverse along the right
                # subtree to the
                # right-most child
                while (current != None):
                    temp = current.right
                    current.right = prev
                    prev = current
                    current = temp
             
                # Traverse back
                # to current's left child
                # node
                while (prev != None):
                    print(prev.data, end = ' ')
                    temp = prev.right
                    prev.right = current
                    current = prev
                    prev = temp
 
                current = succ
                current = current.right
 
# Driver code
if __name__=='__main__':
     
    ''' Constructed tree is as follows:-
                       1
                    /     \
                   2      3
                  / \     / \
                 4   5  6   7
                    / \
                   8   9
        '''
    root = None
 
    root = newNode(1)
    root.left = newNode(2)
    root.right = newNode(3)
 
    root.left.left = newNode(4)
    root.left.right = newNode(5)
 
    root.right.left = newNode(6)
    root.right.right = newNode(7)
 
    root.left.right.left = newNode(8)
    root.left.right.right = newNode(9)
     
    postOrderConstSpace(root)
 
# This code is contributed by pratham76


C#
// C# program to implement
// Post Order traversal
// of Binary Tree in O(N)
// time and O(1) space
using System;
 
// Definition of the
// binary tree
public class  TreeNode
{
    public int data;
    public TreeNode left, right;
   
    public TreeNode(int item)
    {
        data = item;
        left = right = null;
    }
}
 
class PostOrder{
     
public TreeNode root;
 
// Function to find Post Order
// Traversal Using Constant space
void postOrderConstantspace(TreeNode root)
{
    if (root == null)
        return;
   
    TreeNode current = new TreeNode(-1), pre = null;
    TreeNode prev = null,
             succ = null,
             temp = null;
              
    current.left = root;
 
    while (current != null)
    {
         
        // Go to the right child
        // if current does not
        // have a left child
        if (current.left == null)
        {
            current = current.right;
        }
 
        else
        {
             
            // Traverse left child
            pre = current.left;
 
            // Find the right most child
            // in the left subtree
            while (pre.right != null &&
                   pre.right != current)
                pre = pre.right;
 
            if (pre.right == null)
            {
                 
                // Make current as the right
                // child of the right most node
                pre.right = current;
 
                // Traverse the left child
                current = current.left;
            }
            else
            {
                pre.right = null;
                succ = current;
                current = current.left;
                prev = null;
 
                // Traverse along the right
                // subtree to the
                // right-most child
                while (current != null)
                {
                    temp = current.right;
                    current.right = prev;
                    prev = current;
                    current = temp;
                }
 
                // Traverse back from
                // right most child to
                // current's left child node
                while (prev != null)
                {
                   Console.Write(prev.data + " ");
                    temp = prev.right;
                    prev.right = current;
                    current = prev;
                    prev = temp;
                }
                current = succ;
                current = current.right;
            }
        }
    }
}
 
// Driver code
static public void Main ()
{
     
    /* Constructed tree is as follows:-
                      1
                   /     \
                  2       3
                 / \     / \
                4   5   6   7
                   / \
                  8   9
      */
    PostOrder tree = new PostOrder();
    tree.root = new TreeNode(1);
    tree.root.left = new TreeNode(2);
    tree.root.right = new TreeNode(3);
    tree.root.left.left = new TreeNode(4);
    tree.root.left.right = new TreeNode(5);
    tree.root.right.left = new TreeNode(6);
    tree.root.right.right = new TreeNode(7);
    tree.root.left.right.left = new TreeNode(8);
    tree.root.left.right.right = new TreeNode(9);
 
    tree.postOrderConstantspace(tree.root);
}
}
 
// This code is contributed by offbeat


Java
// Java Program to implement
// the above approach
class TreeNode {
    public int data;
    public TreeNode left;
    public TreeNode right;
 
    public TreeNode(int data)
    {
        this.data = data;
    }
 
    public String toString()
    {
        return data + " ";
    }
}
 
public class PostOrder {
    TreeNode root;
 
    // Function to Calculate Post
    // Order Traversal
    // Using Constant Space
    void postOrderConstantspace(TreeNode root)
    {
        if (root == null)
            return;
 
        TreeNode current = null;
        TreeNode prevNode = null;
        TreeNode pre = null;
        TreeNode ptr = null;
        TreeNode netChild = null;
        TreeNode prevPtr = null;
 
        current = root;
        while (current != null) {
            if (current.left == null) {
                current.left = prevNode;
                // Set prevNode to current
                prevNode = current;
                current = current.right;
            }
            else {
                pre = current.left;
                // Find the right most child
                // in the left subtree
                while (pre.right != null
                    && pre.right != current)
                    pre = pre.right;
 
                if (pre.right == null) {
                    pre.right = current;
                    current = current.left;
                }
                else {
                    // Set the right most
                    // child's right pointer
                    // to NULL
                    pre.right = null;
                    System.out.print(pre);
 
                    ptr = pre;
                    netChild = pre;
                    prevPtr = pre;
                    while (ptr != null) {
                        if (ptr.right == netChild) {
                            System.out.print(ptr);
                            netChild = ptr;
                            prevPtr.left = null;
                        }
 
                        if (ptr == current.left)
                            break;
                        // Break the loop
                        // all the left subtree
                        // nodes of current
                        // processed
 
                        prevPtr = ptr;
                        ptr = ptr.left;
                    }
 
                    prevNode = current;
                    current = current.right;
                }
            }
        }
 
        System.out.print(prevNode);
 
        // Last path traversal
        // that includes the root.
        ptr = prevNode;
        netChild = prevNode;
        prevPtr = prevNode;
        while (ptr != null) {
            if (ptr.right == netChild) {
                System.out.print(ptr);
                netChild = ptr;
                prevPtr.left = null;
            }
            if (ptr == root)
                break;
 
            prevPtr = ptr;
            ptr = ptr.left;
        }
    }
 
    // Main Function
    public static void main(String[] args)
    {
        /* Constructed tree is as follows:-
                      1
                   /     \
                  2       3
                 / \     / \
                4   5   6   7
                   / \
                  8   9
      */
        PostOrder tree = new PostOrder();
        tree.root = new TreeNode(1);
        tree.root.left = new TreeNode(2);
        tree.root.right = new TreeNode(3);
        tree.root.left.left
            = new TreeNode(4);
        tree.root.left.right
            = new TreeNode(5);
        tree.root.right.left
            = new TreeNode(6);
        tree.root.right.right
            = new TreeNode(7);
        tree.root.left.right.left
            = new TreeNode(8);
        tree.root.left.right.right
            = new TreeNode(9);
 
        tree.postOrderConstantspace(
            tree.root);
    }
}


C#
// C# Program to implement
// the above approach
using System;
class TreeNode{
     
public int data;
public TreeNode left;
public TreeNode right;
  
public TreeNode(int data)
{
  this.data = data;
}
  
public string toString()
{
  return data + " ";
}
}
  
class PostOrder{
     
TreeNode root;
  
// Function to Calculate Post
// Order Traversal Using
// Constant Space
void postOrderConstantspace(TreeNode root)
{
  if (root == null)
    return;
 
  TreeNode current = null;
  TreeNode prevNode = null;
  TreeNode pre = null;
  TreeNode ptr = null;
  TreeNode netChild = null;
  TreeNode prevPtr = null;
 
  current = root;
   
  while (current != null)
  {
    if (current.left == null)
    {
      current.left = prevNode;
       
      // Set prevNode to current
      prevNode = current;
      current = current.right;
    }
    else
    {
      pre = current.left;
       
      // Find the right most child
      // in the left subtree
      while (pre.right != null &&
             pre.right != current)
        pre = pre.right;
 
      if (pre.right == null)
      {
        pre.right = current;
        current = current.left;
      }
      else
      {
        // Set the right most
        // child's right pointer
        // to NULL
        pre.right = null;
        Console.Write(pre.data + " ");
        ptr = pre;
        netChild = pre;
        prevPtr = pre;
         
        while (ptr != null)
        {
          if (ptr.right == netChild)
          {
            Console.Write(ptr.data + " ");
            netChild = ptr;
            prevPtr.left = null;
          }
 
          if (ptr == current.left)
            break;
           
          // Break the loop
          // all the left subtree
          // nodes of current
          // processed
          prevPtr = ptr;
          ptr = ptr.left;
        }
 
        prevNode = current;
        current = current.right;
      }
    }
  }
 
  Console.Write(prevNode.data + " ");
 
  // Last path traversal
  // that includes the root.
  ptr = prevNode;
  netChild = prevNode;
  prevPtr = prevNode;
   
  while (ptr != null)
  {
    if (ptr.right == netChild)
    {
      Console.Write(ptr.data + " ");
      netChild = ptr;
      prevPtr.left = null;
    }
    if (ptr == root)
      break;
 
    prevPtr = ptr;
    ptr = ptr.left;
  }
}
  
// Driver code
public static void Main(string[] args)
{
  /* Constructed tree is as follows:-
                      1
                   /     \
                  2       3
                 / \     / \
                4   5   6   7
                   / \
                  8   9
      */
  PostOrder tree = new PostOrder();
  tree.root = new TreeNode(1);
  tree.root.left = new TreeNode(2);
  tree.root.right = new TreeNode(3);
  tree.root.left.left = new TreeNode(4);
  tree.root.left.right = new TreeNode(5);
  tree.root.right.left = new TreeNode(6);
  tree.root.right.right = new TreeNode(7);
  tree.root.left.right.left = new TreeNode(8);
  tree.root.left.right.right = new TreeNode(9);
  tree.postOrderConstantspace(tree.root);
}
}
 
// This code is contributed by Rutvik_56


输出
4 8 9 5 2 6 7 3 1

时间复杂度: O(N)
辅助空间: O(1)

方法 2:在方法 1 中,我们遍历路径、反向引用、打印节点,因为我们通过再次反转它们来恢复引用。在方法2中,我们不是使用反向路径和恢复结构,而是使用当前节点的左子树从当前节点遍历到父节点。这可能会更快,具体取决于树结构,例如在右倾斜的树中。

以下算法和图表提供了该方法的详细信息。

下面的概念图显示了如何使用左右子引用来回遍历。

下图突出显示了路径 1->2->5->9 以及按照上述算法处理和打印节点的方式。

下面是上述方法的实现:

Java

// Java Program to implement
// the above approach
class TreeNode {
    public int data;
    public TreeNode left;
    public TreeNode right;
 
    public TreeNode(int data)
    {
        this.data = data;
    }
 
    public String toString()
    {
        return data + " ";
    }
}
 
public class PostOrder {
    TreeNode root;
 
    // Function to Calculate Post
    // Order Traversal
    // Using Constant Space
    void postOrderConstantspace(TreeNode root)
    {
        if (root == null)
            return;
 
        TreeNode current = null;
        TreeNode prevNode = null;
        TreeNode pre = null;
        TreeNode ptr = null;
        TreeNode netChild = null;
        TreeNode prevPtr = null;
 
        current = root;
        while (current != null) {
            if (current.left == null) {
                current.left = prevNode;
                // Set prevNode to current
                prevNode = current;
                current = current.right;
            }
            else {
                pre = current.left;
                // Find the right most child
                // in the left subtree
                while (pre.right != null
                    && pre.right != current)
                    pre = pre.right;
 
                if (pre.right == null) {
                    pre.right = current;
                    current = current.left;
                }
                else {
                    // Set the right most
                    // child's right pointer
                    // to NULL
                    pre.right = null;
                    System.out.print(pre);
 
                    ptr = pre;
                    netChild = pre;
                    prevPtr = pre;
                    while (ptr != null) {
                        if (ptr.right == netChild) {
                            System.out.print(ptr);
                            netChild = ptr;
                            prevPtr.left = null;
                        }
 
                        if (ptr == current.left)
                            break;
                        // Break the loop
                        // all the left subtree
                        // nodes of current
                        // processed
 
                        prevPtr = ptr;
                        ptr = ptr.left;
                    }
 
                    prevNode = current;
                    current = current.right;
                }
            }
        }
 
        System.out.print(prevNode);
 
        // Last path traversal
        // that includes the root.
        ptr = prevNode;
        netChild = prevNode;
        prevPtr = prevNode;
        while (ptr != null) {
            if (ptr.right == netChild) {
                System.out.print(ptr);
                netChild = ptr;
                prevPtr.left = null;
            }
            if (ptr == root)
                break;
 
            prevPtr = ptr;
            ptr = ptr.left;
        }
    }
 
    // Main Function
    public static void main(String[] args)
    {
        /* Constructed tree is as follows:-
                      1
                   /     \
                  2       3
                 / \     / \
                4   5   6   7
                   / \
                  8   9
      */
        PostOrder tree = new PostOrder();
        tree.root = new TreeNode(1);
        tree.root.left = new TreeNode(2);
        tree.root.right = new TreeNode(3);
        tree.root.left.left
            = new TreeNode(4);
        tree.root.left.right
            = new TreeNode(5);
        tree.root.right.left
            = new TreeNode(6);
        tree.root.right.right
            = new TreeNode(7);
        tree.root.left.right.left
            = new TreeNode(8);
        tree.root.left.right.right
            = new TreeNode(9);
 
        tree.postOrderConstantspace(
            tree.root);
    }
}

C#

// C# Program to implement
// the above approach
using System;
class TreeNode{
     
public int data;
public TreeNode left;
public TreeNode right;
  
public TreeNode(int data)
{
  this.data = data;
}
  
public string toString()
{
  return data + " ";
}
}
  
class PostOrder{
     
TreeNode root;
  
// Function to Calculate Post
// Order Traversal Using
// Constant Space
void postOrderConstantspace(TreeNode root)
{
  if (root == null)
    return;
 
  TreeNode current = null;
  TreeNode prevNode = null;
  TreeNode pre = null;
  TreeNode ptr = null;
  TreeNode netChild = null;
  TreeNode prevPtr = null;
 
  current = root;
   
  while (current != null)
  {
    if (current.left == null)
    {
      current.left = prevNode;
       
      // Set prevNode to current
      prevNode = current;
      current = current.right;
    }
    else
    {
      pre = current.left;
       
      // Find the right most child
      // in the left subtree
      while (pre.right != null &&
             pre.right != current)
        pre = pre.right;
 
      if (pre.right == null)
      {
        pre.right = current;
        current = current.left;
      }
      else
      {
        // Set the right most
        // child's right pointer
        // to NULL
        pre.right = null;
        Console.Write(pre.data + " ");
        ptr = pre;
        netChild = pre;
        prevPtr = pre;
         
        while (ptr != null)
        {
          if (ptr.right == netChild)
          {
            Console.Write(ptr.data + " ");
            netChild = ptr;
            prevPtr.left = null;
          }
 
          if (ptr == current.left)
            break;
           
          // Break the loop
          // all the left subtree
          // nodes of current
          // processed
          prevPtr = ptr;
          ptr = ptr.left;
        }
 
        prevNode = current;
        current = current.right;
      }
    }
  }
 
  Console.Write(prevNode.data + " ");
 
  // Last path traversal
  // that includes the root.
  ptr = prevNode;
  netChild = prevNode;
  prevPtr = prevNode;
   
  while (ptr != null)
  {
    if (ptr.right == netChild)
    {
      Console.Write(ptr.data + " ");
      netChild = ptr;
      prevPtr.left = null;
    }
    if (ptr == root)
      break;
 
    prevPtr = ptr;
    ptr = ptr.left;
  }
}
  
// Driver code
public static void Main(string[] args)
{
  /* Constructed tree is as follows:-
                      1
                   /     \
                  2       3
                 / \     / \
                4   5   6   7
                   / \
                  8   9
      */
  PostOrder tree = new PostOrder();
  tree.root = new TreeNode(1);
  tree.root.left = new TreeNode(2);
  tree.root.right = new TreeNode(3);
  tree.root.left.left = new TreeNode(4);
  tree.root.left.right = new TreeNode(5);
  tree.root.right.left = new TreeNode(6);
  tree.root.right.right = new TreeNode(7);
  tree.root.left.right.left = new TreeNode(8);
  tree.root.left.right.right = new TreeNode(9);
  tree.postOrderConstantspace(tree.root);
}
}
 
// This code is contributed by Rutvik_56
输出
4 8 9 5 2 6 7 3 1 

时间复杂度: O(N)
辅助空间: O(1)

如果您想与行业专家一起参加直播课程,请参阅Geeks Classes Live