From b2a951dd656193dbba943e22de3660722dfe9f9f Mon Sep 17 00:00:00 2001 From: santhoshtk Date: Fri, 13 Jan 2023 15:46:22 +0530 Subject: [PATCH] chore(Python): Add Binary Tree Traversals both recursive and iterative method. --- algorithms/Python/README.md | 1 + .../Python/trees/binaryTreeTraversals.py | 197 ++++++++++++++++++ 2 files changed, 198 insertions(+) create mode 100644 algorithms/Python/trees/binaryTreeTraversals.py diff --git a/algorithms/Python/README.md b/algorithms/Python/README.md index 56e61288..27d3c7c3 100644 --- a/algorithms/Python/README.md +++ b/algorithms/Python/README.md @@ -84,6 +84,7 @@ ## Trees - [Binary Tree](trees/binary_tree.py) - [Binary Search Tree](trees/binary_search_tree.py) +- [Binary Tree Traversals](trees/binaryTreeTraversals.py) ## Queues - [First in First out Queue](queues/fifo-queue.py) diff --git a/algorithms/Python/trees/binaryTreeTraversals.py b/algorithms/Python/trees/binaryTreeTraversals.py new file mode 100644 index 00000000..341b8072 --- /dev/null +++ b/algorithms/Python/trees/binaryTreeTraversals.py @@ -0,0 +1,197 @@ +""" +Data Structure : Binary Tree +Algorithm : Binary Tree Traversals (Pre-Order, In-Order, Post-Order) +Time Complexity : O(n) +Space Complexity: O(n) (Auxiliary space) +""" +from typing import Optional, Union +from queue import Queue, LifoQueue +from random import randint + + +class BinaryTreeNode: + """ + Class to represent Binary Tree Node. + Attributes: + - data (int) : The data stored in the `BinaryTreeNode`. + - leftChild (BinaryTreeNode) : The left child of the current node. + - rightChild (BinaryTreeNode) : The right child of the current node. + """ + def __init__(self, data: int) -> None: + self.data = data + self.leftChild: Optional[BinaryTreeNode] = None + self.rightChild: Optional[BinaryTreeNode] = None + + +class BinaryTree: + """ + Class to represent Binary Tree. + Attributes: + - root (BinaryTreeNode) : The root of the Binary Tree. + """ + def __init__(self): + self.root: Optional[BinaryTreeNode] = None + + def insert(self, value: int) -> str: + """ + Create a `BinaryTreeNode` with the `value` and insert the node at the + vacant place in the Binary Tree. + + NOTE : The vacant place can be found using level order traversal. + Also, we need queue for level order traversal. + + :param value: The value of the `BinaryTreeNode`. + :return: A meaningful message to the user of the program. + """ + if not self.root: + self.root = BinaryTreeNode(value) + else: + # Creating the FIFO (Queue) for level order traversal + auxQueue = Queue() + auxQueue.put(self.root) + + while not auxQueue.empty(): + currentNode = auxQueue.get() + + # Check if current node has vacant place. + if currentNode.leftChild is None: + currentNode.leftChild = BinaryTreeNode(value) + break + else: + auxQueue.put(currentNode.leftChild) + + if currentNode.rightChild is None: + currentNode.rightChild = BinaryTreeNode(value) + break + else: + auxQueue.put(currentNode.rightChild) + + return "The value inserted successfully in the Binary Tree." + + +class RecursiveTraversal: + """Class to represent Recursive Traversals of the Binary Tree.""" + def preOrder(self, root: BinaryTreeNode, result: list) -> Union[None, list]: + if not root: + return + else: + result.append(root.data) + self.preOrder(root.leftChild, result) + self.preOrder(root.rightChild, result) + + return result + + def inOrder(self, root: BinaryTreeNode, result: list) -> Union[None, list]: + if not root: + return + else: + self.inOrder(root.leftChild, result) + result.append(root.data) + self.inOrder(root.rightChild, result) + + return result + + def postOrder(self, root: BinaryTreeNode, result: list) -> Union[None, list]: + if not root: + return + else: + self.postOrder(root.leftChild, result) + self.postOrder(root.rightChild, result) + result.append(root.data) + + return result + + +class IterativeTraversal(BinaryTree): + """Class to represent Iterative Traversal for Binary Tree.""" + + def preOrder(self) -> Union[str, list]: + result = [] + + if not self.root: + return "The Binary Tree is Empty." + else: + auxStack = LifoQueue() + auxStack.put(self.root) + + while not auxStack.empty(): + currentNode = auxStack.get() + result.append(currentNode.data) + + # Process right node then left node of the tree. + if currentNode.rightChild: + auxStack.put(currentNode.rightChild) + + if currentNode.leftChild: + auxStack.put(currentNode.leftChild) + + return result + + def inOrder(self) -> Union[str, list]: + result = [] + + if not self.root: + return "The Binary Tree is Empty." + else: + auxStack = LifoQueue() + currentNode = self.root + + while currentNode or not auxStack.empty(): + # Process the left node + if currentNode: + auxStack.put(currentNode) + currentNode = currentNode.leftChild + else: + # Process the right node + currentNode = auxStack.get() + result.append(currentNode.data) + currentNode = currentNode.rightChild + + return result + + def postOrder(self) -> Union[str, list]: + result = [] + + if not self.root: + return "The Binary Tree is Empty." + else: + auxStack = [] + previous: Optional[BinaryTreeNode] = None + currentNode = self.root + + while currentNode or auxStack: + # Process the left node + while currentNode: + auxStack.append(currentNode) + currentNode = currentNode.leftChild + + currentNode = auxStack[-1] + + # Process the current node if it is the second visit. + if not currentNode.rightChild or previous == currentNode.rightChild: + previous = auxStack.pop() + result.append(previous.data) + currentNode = None + else: + currentNode = currentNode.rightChild + + return result + + +if __name__ == "__main__": + + bTree = IterativeTraversal() + # Create Binary Tree with random values + for _ in range(15): + bTree.insert(randint(0, 1000)) + + print("Iterative Outputs") + print(bTree.preOrder()) + print(bTree.inOrder()) + print(bTree.postOrder()) + + print("\nRecursive Outputs") + recursion = RecursiveTraversal() + print(recursion.preOrder(bTree.root, [])) + print(recursion.inOrder(bTree.root, [])) + print(recursion.postOrder(bTree.root, []))