-
-
Notifications
You must be signed in to change notification settings - Fork 46.6k
/
Copy pathbinary_tree_traversals.py
250 lines (189 loc) · 6.13 KB
/
binary_tree_traversals.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
# https://en.wikipedia.org/wiki/Tree_traversal
from __future__ import annotations
from collections import deque
from collections.abc import Sequence
from dataclasses import dataclass
from typing import Any
@dataclass
class Node:
data: int
left: Node | None = None
right: Node | None = None
def make_tree() -> Node | None:
r"""
The below tree
1
/ \
2 3
/ \
4 5
"""
tree = Node(1)
tree.left = Node(2)
tree.right = Node(3)
tree.left.left = Node(4)
tree.left.right = Node(5)
return tree
def preorder(root: Node | None) -> Sequence[int]:
"""
Lazy preorder traversal of a binary tree.
Args:
root: The root node of the binary tree.
Yields:
The values of nodes in the tree using lazy traversal.
"""
if not root:
return
yield root.data
yield from preorder(root.left)
yield from preorder(root.right)
def postorder(root: Node | None) -> Sequence[int]:
"""
Lazy post-order traversal of a binary tree.
Args:
root: The root node of the binary tree.
Yields:
The values of nodes in the tree using lazy traversal.
"""
if not root:
return
yield from postorder(root.left)
yield from postorder(root.right)
yield root.data
def inorder(root: Node | None) -> Sequence[int]:
"""
Lazy in-order traversal of a binary tree.
Args:
root: The root node of the binary tree.
Yields:
The values of nodes in the tree using lazy traversal.
"""
if not root:
return
yield from inorder(root.left)
yield root.data
yield from inorder(root.right)
def reverse_inorder(root: Node | None) -> Sequence[int]:
"""
Lazy reverse in-order traversal of a binary tree.
Args:
root: The root node of the binary tree.
Yields:
The values of nodes in the tree using lazy traversal.
"""
if not root:
return
yield from reverse_inorder(root.right)
yield root.data
yield from reverse_inorder(root.left)
def height(root: Node | None) -> int:
"""
Recursive function for calculating the height of the binary tree.
Args:
root: The root node of the binary tree.
Returns:
The height of the binary tree.
"""
return (max(height(root.left), height(root.right)) + 1) if root else 0
def level_order(root: Node | None) -> Sequence[int]:
"""
Lazy level order traversal of a binary tree.
Args:
root: The root node of the binary tree.
Yields:
The values of nodes in the tree using lazy traversal.
"""
if root is None:
return
process_queue = deque([root])
while process_queue:
node = process_queue.popleft()
yield node.data
if node.left:
process_queue.append(node.left)
if node.right:
process_queue.append(node.right)
def get_nodes_from_left_to_right(
root: Node | None, level: int
) -> Sequence[int]:
"""
Lazy traversal to get nodes from left to right at a particular level of a binary tree.
Args:
root: The root node of the binary tree.
level: The level at which nodes are retrieved.
Yields:
The values of nodes at the specified level using lazy traversal.
"""
if not root:
return
def populate_output(root: Node | None, level: int) -> None:
if not root:
return
if level == 1:
yield root.data
elif level > 1:
yield from populate_output(root.left, level - 1)
yield from populate_output(root.right, level - 1)
yield from populate_output(root, level)
def get_nodes_from_right_to_left(
root: Node | None, level: int
) -> Sequence[int]:
"""
Lazy traversal to get nodes from right to left at a particular level of a binary tree.
Args:
root: The root node of the binary tree.
level: The level at which nodes are retrieved.
Yields:
The values of nodes at the specified level using lazy traversal.
"""
if not root:
return
def populate_output(root: Node | None, level: int) -> None:
if not root:
return
if level == 1:
yield root.data
elif level > 1:
yield from populate_output(root.right, level - 1)
yield from populate_output(root.left, level - 1)
yield from populate_output(root, level)
def zigzag(root: Node | None) -> Sequence[Node | None] | list[Any]:
"""
ZigZag traverse:
Returns a list of nodes value from left to right and right to left, alternatively.
Args:
root: The root node of the binary tree.
Yields:
The values of nodes in a zigzag order using lazy traversal.
"""
if root is None:
return
flag = 0
height_tree = height(root)
for h in range(1, height_tree + 1):
if not flag:
yield from get_nodes_from_left_to_right(root, h)
flag = 1
else:
yield from get_nodes_from_right_to_left(root, h)
flag = 0
def main() -> None: # Main function for testing.
# Create binary tree.
root = make_tree()
# All Traversals of the binary are as follows:
print(f"In-order Traversal: {list(inorder(root))}")
print(f"Reverse In-order Traversal: {list(reverse_inorder(root))}")
print(f"Pre-order Traversal: {list(preorder(root))}")
print(f"Post-order Traversal: {list(postorder(root))}", "\n")
print(f"Height of Tree: {height(root)}", "\n")
print("Complete Level Order Traversal: ")
print(list(level_order(root)), "\n")
print("Level-wise order Traversal: ")
for level in range(1, height(root) + 1):
print(f"Level {level}:", list(get_nodes_from_left_to_right(root, level=level)))
print("\nZigZag order Traversal: ")
print(list(zigzag(root)))
if __name__ == "__main__":
import doctest
doctest.testmod()
main()