Article Categories
- All Categories
-
Data Structure
-
Networking
-
RDBMS
-
Operating System
-
Java
-
MS Excel
-
iOS
-
HTML
-
CSS
-
Android
-
Python
-
C Programming
-
C++
-
C#
-
MongoDB
-
MySQL
-
Javascript
-
PHP
-
Economics & Finance
Construct a Binary Tree from Postorder and Inorder in Python
Building a binary tree from inorder and postorder traversals is a classic tree reconstruction problem. Given these two traversal sequences, we can uniquely reconstruct the original binary tree by leveraging the properties of each traversal type.
Algorithm Approach
The key insight is that in postorder traversal, the last element is always the root of the tree. We can use this root to split the inorder sequence into left and right subtrees.
Implementation
class TreeNode:
def __init__(self, data, left=None, right=None):
self.data = data
self.left = left
self.right = right
def print_inorder(root):
"""Print inorder traversal of the tree"""
if root is not None:
print_inorder(root.left)
print(root.data, end=', ')
print_inorder(root.right)
class Solution:
def buildTree(self, inorder, postorder):
"""
Build binary tree from inorder and postorder traversals
"""
if inorder:
# Last element in postorder is the root
root = TreeNode(postorder.pop())
# Find root's position in inorder
root_index = inorder.index(root.data)
# Build right subtree first (postorder processes right before left)
root.right = self.buildTree(inorder[root_index + 1:], postorder)
# Build left subtree
root.left = self.buildTree(inorder[:root_index], postorder)
return root
# Example usage
solution = Solution()
inorder_seq = [9, 3, 15, 20, 7]
postorder_seq = [9, 15, 7, 20, 3]
tree = solution.buildTree(inorder_seq, postorder_seq)
print("Reconstructed tree (inorder):")
print_inorder(tree)
Reconstructed tree (inorder): 9, 3, 15, 20, 7,
How It Works
The algorithm works by recursively identifying roots and splitting sequences:
- Root Identification: The last element in postorder is always the current subtree's root
- Sequence Splitting: Find the root in inorder to determine left and right subtree elements
- Recursive Construction: Build right subtree first, then left (due to postorder's right-to-left processing)
Step-by-Step Execution
class TreeNodeWithSteps:
def __init__(self, data):
self.data = data
self.left = None
self.right = None
def build_tree_with_steps(inorder, postorder, level=0):
"""Build tree with step-by-step explanation"""
indent = " " * level
if not inorder:
print(f"{indent}Empty sequence - returning None")
return None
# Get root from postorder
root_val = postorder.pop()
root = TreeNodeWithSteps(root_val)
print(f"{indent}Root: {root_val}")
# Find root position in inorder
root_index = inorder.index(root_val)
print(f"{indent}Left subtree: {inorder[:root_index]}")
print(f"{indent}Right subtree: {inorder[root_index + 1:]}")
# Build subtrees
root.right = build_tree_with_steps(inorder[root_index + 1:], postorder, level + 1)
root.left = build_tree_with_steps(inorder[:root_index], postorder, level + 1)
return root
# Demonstrate step-by-step construction
print("Step-by-step tree construction:")
inorder_demo = [9, 3, 15, 20, 7]
postorder_demo = [9, 15, 7, 20, 3]
result = build_tree_with_steps(inorder_demo, postorder_demo)
Step-by-step tree construction:
Root: 3
Left subtree: [9]
Right subtree: [15, 20, 7]
Root: 20
Left subtree: [15]
Right subtree: [7]
Root: 7
Left subtree: []
Right subtree: []
Empty sequence - returning None
Empty sequence - returning None
Root: 15
Left subtree: []
Right subtree: []
Empty sequence - returning None
Empty sequence - returning None
Root: 9
Left subtree: []
Right subtree: []
Empty sequence - returning None
Empty sequence - returning None
Time and Space Complexity
| Aspect | Complexity | Explanation |
|---|---|---|
| Time | O(n²) | Finding index in inorder for each node |
| Space | O(n) | Recursion stack and tree storage |
Optimized Version
class OptimizedSolution:
def buildTree(self, inorder, postorder):
"""
Optimized version using hashmap for O(1) index lookup
"""
# Create hashmap for O(1) index lookup
inorder_map = {val: i for i, val in enumerate(inorder)}
def build(in_start, in_end):
if in_start > in_end:
return None
# Get root from postorder
root_val = postorder.pop()
root = TreeNode(root_val)
# Find root position using hashmap
root_index = inorder_map[root_val]
# Build right first, then left
root.right = build(root_index + 1, in_end)
root.left = build(in_start, root_index - 1)
return root
return build(0, len(inorder) - 1)
# Test optimized version
optimized_solution = OptimizedSolution()
inorder_test = [9, 3, 15, 20, 7]
postorder_test = [9, 15, 7, 20, 3]
optimized_tree = optimized_solution.buildTree(inorder_test, postorder_test)
print("Optimized solution result (inorder):")
print_inorder(optimized_tree)
Optimized solution result (inorder): 9, 3, 15, 20, 7,
Conclusion
Constructing a binary tree from inorder and postorder traversals involves using the last element of postorder as the root and recursively building subtrees. The optimized version using a hashmap reduces time complexity from O(n²) to O(n) by eliminating linear index searches.
