binary_search_traversals.py made memory-friendly using generators. Fixes #8725 completely. (#9237)

* Made binary tree memory-friendly using generators based travels. Fixes
#8725

* Made binary tree memory-friendly using generators based travels. Fixes
#8725

* Fixed pre-commit errors
This commit is contained in:
aryan1165 2023-10-01 22:24:05 +05:30 committed by GitHub
parent bacad12a1f
commit 18cdbc4165
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -1,9 +1,8 @@
from __future__ import annotations from __future__ import annotations
from collections import deque from collections import deque
from collections.abc import Generator, Sequence from collections.abc import Generator
from dataclasses import dataclass from dataclasses import dataclass
from typing import Any
# https://en.wikipedia.org/wiki/Tree_traversal # https://en.wikipedia.org/wiki/Tree_traversal
@ -94,96 +93,86 @@ def height(root: Node | None) -> int:
return (max(height(root.left), height(root.right)) + 1) if root else 0 return (max(height(root.left), height(root.right)) + 1) if root else 0
def level_order(root: Node | None) -> Sequence[Node | None]: def level_order(root: Node | None) -> Generator[int, None, None]:
""" """
Returns a list of nodes value from a whole binary tree in Level Order Traverse. Returns a list of nodes value from a whole binary tree in Level Order Traverse.
Level Order traverse: Visit nodes of the tree level-by-level. Level Order traverse: Visit nodes of the tree level-by-level.
""" """
output: list[Any] = []
if root is None: if root is None:
return output return
process_queue = deque([root]) process_queue = deque([root])
while process_queue: while process_queue:
node = process_queue.popleft() node = process_queue.popleft()
output.append(node.data) yield node.data
if node.left: if node.left:
process_queue.append(node.left) process_queue.append(node.left)
if node.right: if node.right:
process_queue.append(node.right) process_queue.append(node.right)
return output
def get_nodes_from_left_to_right( def get_nodes_from_left_to_right(
root: Node | None, level: int root: Node | None, level: int
) -> Sequence[Node | None]: ) -> Generator[int, None, None]:
""" """
Returns a list of nodes value from a particular level: Returns a list of nodes value from a particular level:
Left to right direction of the binary tree. Left to right direction of the binary tree.
""" """
output: list[Any] = []
def populate_output(root: Node | None, level: int) -> None: def populate_output(root: Node | None, level: int) -> Generator[int, None, None]:
if not root: if not root:
return return
if level == 1: if level == 1:
output.append(root.data) yield root.data
elif level > 1: elif level > 1:
populate_output(root.left, level - 1) yield from populate_output(root.left, level - 1)
populate_output(root.right, level - 1) yield from populate_output(root.right, level - 1)
populate_output(root, level) yield from populate_output(root, level)
return output
def get_nodes_from_right_to_left( def get_nodes_from_right_to_left(
root: Node | None, level: int root: Node | None, level: int
) -> Sequence[Node | None]: ) -> Generator[int, None, None]:
""" """
Returns a list of nodes value from a particular level: Returns a list of nodes value from a particular level:
Right to left direction of the binary tree. Right to left direction of the binary tree.
""" """
output: list[Any] = []
def populate_output(root: Node | None, level: int) -> None: def populate_output(root: Node | None, level: int) -> Generator[int, None, None]:
if root is None: if root is None:
return return
if level == 1: if level == 1:
output.append(root.data) yield root.data
elif level > 1: elif level > 1:
populate_output(root.right, level - 1) yield from populate_output(root.right, level - 1)
populate_output(root.left, level - 1) yield from populate_output(root.left, level - 1)
populate_output(root, level) yield from populate_output(root, level)
return output
def zigzag(root: Node | None) -> Sequence[Node | None] | list[Any]: def zigzag(root: Node | None) -> Generator[int, None, None]:
""" """
ZigZag traverse: ZigZag traverse:
Returns a list of nodes value from left to right and right to left, alternatively. Returns a list of nodes value from left to right and right to left, alternatively.
""" """
if root is None: if root is None:
return [] return
output: list[Sequence[Node | None]] = []
flag = 0 flag = 0
height_tree = height(root) height_tree = height(root)
for h in range(1, height_tree + 1): for h in range(1, height_tree + 1):
if not flag: if not flag:
output.append(get_nodes_from_left_to_right(root, h)) yield from get_nodes_from_left_to_right(root, h)
flag = 1 flag = 1
else: else:
output.append(get_nodes_from_right_to_left(root, h)) yield from get_nodes_from_right_to_left(root, h)
flag = 0 flag = 0
return output
def main() -> None: # Main function for testing. def main() -> None: # Main function for testing.
# Create binary tree. # Create binary tree.
@ -198,15 +187,15 @@ def main() -> None: # Main function for testing.
print(f"Height of Tree: {height(root)}", "\n") print(f"Height of Tree: {height(root)}", "\n")
print("Complete Level Order Traversal: ") print("Complete Level Order Traversal: ")
print(level_order(root), "\n") print(f"{list(level_order(root))} \n")
print("Level-wise order Traversal: ") print("Level-wise order Traversal: ")
for level in range(1, height(root) + 1): for level in range(1, height(root) + 1):
print(f"Level {level}:", get_nodes_from_left_to_right(root, level=level)) print(f"Level {level}:", list(get_nodes_from_left_to_right(root, level=level)))
print("\nZigZag order Traversal: ") print("\nZigZag order Traversal: ")
print(zigzag(root)) print(f"{list(zigzag(root))}")
if __name__ == "__main__": if __name__ == "__main__":