|
1 | | -# Binary Tree Node class |
| 1 | +""" |
| 2 | +Build a binary tree from preorder + inorder or postorder + inorder traversals. |
| 3 | +
|
| 4 | +This module provides two main functions: |
| 5 | +- build_tree_from_preorder_and_inorder() |
| 6 | +- build_tree_from_postorder_and_inorder() |
| 7 | +
|
| 8 | +Each builds a binary tree represented by Node objects. |
| 9 | +
|
| 10 | +References: |
| 11 | + - https://en.wikipedia.org/wiki/Binary_tree |
| 12 | + - https://en.wikipedia.org/wiki/Tree_traversal |
| 13 | +""" |
| 14 | + |
| 15 | +from typing import Dict, List, Optional |
| 16 | + |
| 17 | + |
2 | 18 | class Node: |
3 | | - def __init__(self, data): |
4 | | - self.data = data |
5 | | - self.left = None |
6 | | - self.right = None |
| 19 | + """ |
| 20 | + A class representing a node in a binary tree. |
7 | 21 |
|
| 22 | + Attributes: |
| 23 | + data (int): The value of the node. |
| 24 | + left (Optional[Node]): Pointer to the left child. |
| 25 | + right (Optional[Node]): Pointer to the right child. |
| 26 | + """ |
8 | 27 |
|
9 | | -# Normal inorder traversal |
10 | | -def inorder(root, out): |
11 | | - """Perform inorder traversal and append values to 'out' list.""" |
12 | | - if root is None: |
13 | | - return |
14 | | - inorder(root.left, out) |
15 | | - out.append(root.data) |
16 | | - inorder(root.right, out) |
| 28 | + def __init__(self, data: int) -> None: |
| 29 | + self.data = data |
| 30 | + self.left: Optional[Node] = None |
| 31 | + self.right: Optional[Node] = None |
17 | 32 |
|
18 | 33 |
|
19 | | -# === Build tree using PREORDER + INORDER === |
20 | | -def build_tree_from_pre( |
21 | | - preorder, pre_start, pre_end, inorder_seq, in_start, in_end, in_map |
22 | | -): |
23 | | - """Recursive helper to build tree from preorder and inorder traversal.""" |
| 34 | +def inorder_traversal(root: Optional[Node]) -> List[int]: |
| 35 | + """ |
| 36 | + Return the inorder traversal of a binary tree as a list. |
| 37 | +
|
| 38 | + >>> root = Node(3) |
| 39 | + >>> root.left = Node(2) |
| 40 | + >>> root.right = Node(4) |
| 41 | + >>> inorder_traversal(root) |
| 42 | + [2, 3, 4] |
| 43 | + """ |
| 44 | + if root is None: |
| 45 | + return [] |
| 46 | + return inorder_traversal(root.left) + [root.data] + inorder_traversal(root.right) |
| 47 | + |
| 48 | + |
| 49 | +def _build_tree_from_preorder( |
| 50 | + preorder: List[int], |
| 51 | + pre_start: int, |
| 52 | + pre_end: int, |
| 53 | + inorder_seq: List[int], |
| 54 | + in_start: int, |
| 55 | + in_end: int, |
| 56 | + inorder_map: Dict[int, int], |
| 57 | +) -> Optional[Node]: |
| 58 | + """Helper function for building a tree recursively from preorder + inorder.""" |
24 | 59 | if pre_start > pre_end or in_start > in_end: |
25 | 60 | return None |
26 | 61 |
|
27 | | - # Root is the first element in current preorder segment |
28 | | - root_val = preorder[pre_start] |
29 | | - root = Node(root_val) |
30 | | - |
31 | | - # Find the root index in inorder traversal |
32 | | - in_root_index = in_map[root_val] |
33 | | - nums_left = in_root_index - in_start |
| 62 | + root_value = preorder[pre_start] |
| 63 | + root = Node(root_value) |
| 64 | + in_root_index = inorder_map[root_value] |
| 65 | + left_subtree_size = in_root_index - in_start |
34 | 66 |
|
35 | | - # Recursively build left and right subtrees |
36 | | - root.left = build_tree_from_pre( |
| 67 | + root.left = _build_tree_from_preorder( |
37 | 68 | preorder, |
38 | 69 | pre_start + 1, |
39 | | - pre_start + nums_left, |
| 70 | + pre_start + left_subtree_size, |
40 | 71 | inorder_seq, |
41 | 72 | in_start, |
42 | 73 | in_root_index - 1, |
43 | | - in_map, |
| 74 | + inorder_map, |
44 | 75 | ) |
45 | | - |
46 | | - root.right = build_tree_from_pre( |
| 76 | + root.right = _build_tree_from_preorder( |
47 | 77 | preorder, |
48 | | - pre_start + nums_left + 1, |
| 78 | + pre_start + left_subtree_size + 1, |
49 | 79 | pre_end, |
50 | 80 | inorder_seq, |
51 | 81 | in_root_index + 1, |
52 | 82 | in_end, |
53 | | - in_map, |
| 83 | + inorder_map, |
54 | 84 | ) |
55 | | - |
56 | 85 | return root |
57 | 86 |
|
58 | 87 |
|
59 | | -def build_tree_pre(inorder_seq, preorder_seq): |
60 | | - """Wrapper function for building tree from preorder + inorder.""" |
61 | | - in_map = {val: i for i, val in enumerate(inorder_seq)} |
62 | | - return build_tree_from_pre( |
| 88 | +def build_tree_from_preorder_and_inorder( |
| 89 | + inorder_seq: List[int], preorder_seq: List[int] |
| 90 | +) -> Optional[Node]: |
| 91 | + """ |
| 92 | + Build a binary tree from preorder and inorder traversals. |
| 93 | +
|
| 94 | + Args: |
| 95 | + inorder_seq: The inorder traversal sequence. |
| 96 | + preorder_seq: The preorder traversal sequence. |
| 97 | +
|
| 98 | + Returns: |
| 99 | + Root node of the reconstructed binary tree. |
| 100 | +
|
| 101 | + >>> inorder_seq = [1, 2, 3, 4, 5] |
| 102 | + >>> preorder_seq = [3, 2, 1, 4, 5] |
| 103 | + >>> root = build_tree_from_preorder_and_inorder(inorder_seq, preorder_seq) |
| 104 | + >>> inorder_traversal(root) |
| 105 | + [1, 2, 3, 4, 5] |
| 106 | + """ |
| 107 | + inorder_map = {value: i for i, value in enumerate(inorder_seq)} |
| 108 | + return _build_tree_from_preorder( |
63 | 109 | preorder_seq, |
64 | 110 | 0, |
65 | 111 | len(preorder_seq) - 1, |
66 | 112 | inorder_seq, |
67 | 113 | 0, |
68 | 114 | len(inorder_seq) - 1, |
69 | | - in_map, |
| 115 | + inorder_map, |
70 | 116 | ) |
71 | 117 |
|
72 | 118 |
|
73 | | -# === Build tree using POSTORDER + INORDER === |
74 | | -def build_tree_from_post( |
75 | | - postorder, post_start, post_end, inorder_seq, in_start, in_end, in_map |
76 | | -): |
77 | | - """Recursive helper to build tree from postorder and inorder traversal.""" |
| 119 | +def _build_tree_from_postorder( |
| 120 | + postorder: List[int], |
| 121 | + post_start: int, |
| 122 | + post_end: int, |
| 123 | + inorder_seq: List[int], |
| 124 | + in_start: int, |
| 125 | + in_end: int, |
| 126 | + inorder_map: Dict[int, int], |
| 127 | +) -> Optional[Node]: |
| 128 | + """Helper function for building a tree recursively from postorder + inorder.""" |
78 | 129 | if post_start > post_end or in_start > in_end: |
79 | 130 | return None |
80 | 131 |
|
81 | | - # Root is the last element in current postorder segment |
82 | | - root_val = postorder[post_end] |
83 | | - root = Node(root_val) |
84 | | - |
85 | | - # Find the root index in inorder traversal |
86 | | - in_root_index = in_map[root_val] |
87 | | - nums_left = in_root_index - in_start |
| 132 | + root_value = postorder[post_end] |
| 133 | + root = Node(root_value) |
| 134 | + in_root_index = inorder_map[root_value] |
| 135 | + left_subtree_size = in_root_index - in_start |
88 | 136 |
|
89 | | - # Recursively build left and right subtrees |
90 | | - root.left = build_tree_from_post( |
| 137 | + root.left = _build_tree_from_postorder( |
91 | 138 | postorder, |
92 | 139 | post_start, |
93 | | - post_start + nums_left - 1, |
| 140 | + post_start + left_subtree_size - 1, |
94 | 141 | inorder_seq, |
95 | 142 | in_start, |
96 | 143 | in_root_index - 1, |
97 | | - in_map, |
| 144 | + inorder_map, |
98 | 145 | ) |
99 | | - |
100 | | - root.right = build_tree_from_post( |
| 146 | + root.right = _build_tree_from_postorder( |
101 | 147 | postorder, |
102 | | - post_start + nums_left, |
| 148 | + post_start + left_subtree_size, |
103 | 149 | post_end - 1, |
104 | 150 | inorder_seq, |
105 | 151 | in_root_index + 1, |
106 | 152 | in_end, |
107 | | - in_map, |
| 153 | + inorder_map, |
108 | 154 | ) |
109 | | - |
110 | 155 | return root |
111 | 156 |
|
112 | 157 |
|
113 | | -def build_tree_post(inorder_seq, postorder_seq): |
114 | | - """Wrapper function for building tree from postorder + inorder.""" |
115 | | - in_map = {val: i for i, val in enumerate(inorder_seq)} |
116 | | - return build_tree_from_post( |
| 158 | +def build_tree_from_postorder_and_inorder( |
| 159 | + inorder_seq: List[int], postorder_seq: List[int] |
| 160 | +) -> Optional[Node]: |
| 161 | + """ |
| 162 | + Build a binary tree from postorder and inorder traversals. |
| 163 | +
|
| 164 | + Args: |
| 165 | + inorder_seq: The inorder traversal sequence. |
| 166 | + postorder_seq: The postorder traversal sequence. |
| 167 | +
|
| 168 | + Returns: |
| 169 | + Root node of the reconstructed binary tree. |
| 170 | +
|
| 171 | + >>> inorder_seq = [1, 2, 3, 4, 5] |
| 172 | + >>> postorder_seq = [1, 2, 5, 4, 3] |
| 173 | + >>> root = build_tree_from_postorder_and_inorder(inorder_seq, postorder_seq) |
| 174 | + >>> inorder_traversal(root) |
| 175 | + [1, 2, 3, 4, 5] |
| 176 | + """ |
| 177 | + inorder_map = {value: i for i, value in enumerate(inorder_seq)} |
| 178 | + return _build_tree_from_postorder( |
117 | 179 | postorder_seq, |
118 | 180 | 0, |
119 | 181 | len(postorder_seq) - 1, |
120 | 182 | inorder_seq, |
121 | 183 | 0, |
122 | 184 | len(inorder_seq) - 1, |
123 | | - in_map, |
| 185 | + inorder_map, |
124 | 186 | ) |
125 | 187 |
|
126 | 188 |
|
127 | | -# === Example === |
128 | 189 | if __name__ == "__main__": |
| 190 | + # Example usage for manual verification (not part of algorithmic test) |
129 | 191 | inorder_seq = [1, 2, 3, 4, 5] |
130 | 192 | preorder_seq = [3, 2, 1, 4, 5] |
131 | 193 | postorder_seq = [1, 2, 5, 4, 3] |
132 | 194 |
|
133 | | - print("=== Build BST from Preorder & Inorder ===") |
134 | | - tree_pre = build_tree_pre(inorder_seq, preorder_seq) |
135 | | - out = [] |
136 | | - inorder(tree_pre, out) |
137 | | - print("Inorder:", *out) |
138 | | - |
139 | | - print("=== Build BST from Postorder & Inorder ===") |
140 | | - tree_post = build_tree_post(inorder_seq, postorder_seq) |
141 | | - out = [] |
142 | | - inorder(tree_post, out) |
143 | | - print("Inorder:", *out) |
| 195 | + root_pre = build_tree_from_preorder_and_inorder(inorder_seq, preorder_seq) |
| 196 | + print("Inorder (from Preorder+Inorder):", inorder_traversal(root_pre)) |
| 197 | + |
| 198 | + root_post = build_tree_from_postorder_and_inorder(inorder_seq, postorder_seq) |
| 199 | + print("Inorder (from Postorder+Inorder):", inorder_traversal(root_post)) |
0 commit comments