mirror of
https://github.com/autistic-symposium/master-algorithms-py.git
synced 2025-04-29 12:16:14 -04:00
297 lines
8.7 KiB
Python
297 lines
8.7 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
# author: bt3gl
|
|
|
|
|
|
class SimpleTree:
|
|
"""Implementation of a simple tree"""
|
|
|
|
def __init__(self, value=None, node=None):
|
|
self.value = value
|
|
self.node = node or []
|
|
|
|
def __repr__(self, level=0):
|
|
repr = '\t' * level + self.value + '\n'
|
|
for n in self.node:
|
|
repr += n.__repr__(level + 1)
|
|
return repr
|
|
|
|
|
|
class Node():
|
|
"""Implementation of a Node for a binary tree"""
|
|
|
|
def __init__(self, value=None):
|
|
self.value = value
|
|
self.left = None
|
|
self.right = None
|
|
|
|
############################
|
|
# Private Methods
|
|
############################
|
|
def __repr__(self):
|
|
"""Prints the node"""
|
|
return f'{self.value}'
|
|
|
|
def _repr_preorder(self):
|
|
"""Prints the tree in preorder traversal (root, left, right)"""
|
|
|
|
print(self.value)
|
|
if self.left:
|
|
self.left._repr_preorder()
|
|
if self.right:
|
|
self.right._repr_preorder()
|
|
|
|
def _add_node_binary_tree(self, value):
|
|
"""Adds a node to a simple binary tree"""
|
|
|
|
if self.value is None:
|
|
self.value = value
|
|
|
|
else:
|
|
if not self.left:
|
|
self.left = Node(value)
|
|
elif not self.right:
|
|
self.right = Node(value)
|
|
else:
|
|
self.left = self.left._add_node_binary_tree(value)
|
|
|
|
return self
|
|
|
|
def _add_node_binary_search_tree(self, value) -> bool:
|
|
"""Adds a node to a binary search tree"""
|
|
|
|
if not self.value:
|
|
self.value = value
|
|
|
|
else:
|
|
new_node = Node(value)
|
|
if value < self.value:
|
|
self.left = self.left and self.left._add_node_binary_search_tree(value) or new_node
|
|
elif value > self.value:
|
|
self.right = self.right and self.right._add_node_binary_search_tree(value) or new_node
|
|
else:
|
|
print(f'❌ Item {value} not added as BSTs do not support repetition.')
|
|
|
|
return self
|
|
|
|
def _search_node_preorder(self, query) -> bool:
|
|
"""Searches through preorder traversal (node, left, right)"""
|
|
|
|
if self.value == query:
|
|
return True
|
|
|
|
found = False
|
|
if self.left:
|
|
# recursively search left
|
|
found = self.left._search_node_preorder(query)
|
|
|
|
if self.right:
|
|
# recursively search right
|
|
found = found or self.right._search_node_preorder(query)
|
|
|
|
return found
|
|
|
|
def _search_node_binary_search_tree(self, query) -> bool:
|
|
"""Searches the tree for a value, considering the BST property"""
|
|
|
|
this_node_value = self.value
|
|
|
|
if this_node_value is not None:
|
|
if this_node_value == query:
|
|
return True
|
|
|
|
elif this_node_value > query:
|
|
if self.left is not None:
|
|
return self.left._search_node_binary_search_tree(query)
|
|
|
|
elif this_node_value < query:
|
|
if self.right is not None:
|
|
return self.right._search_node_binary_search_tree(query)
|
|
|
|
return False
|
|
|
|
def _is_leaf(self) -> bool:
|
|
"""If node has no children, it is a leaf"""
|
|
|
|
return bool(not self.right and not self.left)
|
|
|
|
def _is_full(self) -> bool:
|
|
"""If node has two children, it is full"""
|
|
return bool(self.right and self.left)
|
|
|
|
|
|
class BinaryTreeInterface():
|
|
|
|
def __init__(self):
|
|
self.root = Node()
|
|
|
|
############################
|
|
# Interface Methods
|
|
############################
|
|
def add_node(self, value):
|
|
"""Adds a new node to the tree"""
|
|
pass
|
|
|
|
def search_node(self, value):
|
|
"""Searches the tree for a value"""
|
|
pass
|
|
|
|
############################
|
|
# Public Methods
|
|
############################
|
|
def is_leaf(self) -> bool:
|
|
"""Returns True if the node is a leaf"""
|
|
|
|
if self.root is not None:
|
|
return self.root._is_leaf()
|
|
|
|
def is_full(self) -> bool:
|
|
"""Returns True if the node is full"""
|
|
|
|
if self.root is not None:
|
|
return self.root._is_full()
|
|
|
|
def print_preorder(self):
|
|
"""Prints the BST in preorder"""
|
|
|
|
if self.root is not None:
|
|
self.root._repr_preorder()
|
|
|
|
############################
|
|
# Class Methods
|
|
############################
|
|
@classmethod
|
|
def is_balanced(cls, node, left=0, right=0) -> bool:
|
|
"""Returns True if the tree is balanced"""
|
|
|
|
if node is None:
|
|
return (left - right) < 2
|
|
|
|
else:
|
|
return cls.is_balanced(node.left, left + 1, right) and \
|
|
cls.is_balanced(node.right, left, right + 1)
|
|
|
|
@classmethod
|
|
def is_binary_search_tree(cls, node, min_node=None, max_node=None) -> bool:
|
|
"""Returns True if the tree is a BST"""
|
|
|
|
min_node = min_node or float('-inf')
|
|
max_node = max_node or float('inf')
|
|
|
|
if not node:
|
|
return True
|
|
|
|
if node.value < min_node or node.value > max_node:
|
|
return False
|
|
|
|
return cls.is_binary_search_tree(node.left, min_node, node.value) and \
|
|
cls.is_binary_search_tree(node.right, node.value, max_node)
|
|
|
|
|
|
|
|
class BinaryTree(BinaryTreeInterface):
|
|
"""Implementation of a binary tree"""
|
|
|
|
def add_node(self, value):
|
|
"""Adds a new node to the tree"""
|
|
|
|
if self.root is None:
|
|
self.root = Node(value)
|
|
else:
|
|
self.root._add_node_binary_tree(value)
|
|
|
|
def search_node(self, value):
|
|
"""Searches the tree for a value"""
|
|
|
|
if self.root:
|
|
return self.root._search_node_preorder(value)
|
|
|
|
|
|
class BinarySearchTree(BinaryTreeInterface):
|
|
|
|
def add_node(self, value):
|
|
"""Adds a new node to the tree"""
|
|
|
|
if self.root is None:
|
|
self.root = Node(value)
|
|
else:
|
|
self.root._add_node_binary_search_tree(value)
|
|
|
|
def search_node(self, value):
|
|
"""Searches the tree for a value"""
|
|
|
|
if self.root.value is not None:
|
|
return self.root._search_node_binary_search_tree(value)
|
|
|
|
@classmethod
|
|
def largest_node(cls, node):
|
|
"""Returns the largest node in the tree"""
|
|
|
|
if node.right:
|
|
return cls.largest_node(node.right)
|
|
else:
|
|
return node
|
|
|
|
@classmethod
|
|
def smallest_node(cls, node):
|
|
"""Returns the smallest node in the tree"""
|
|
|
|
if node.left:
|
|
return cls.smallest_node(node.left)
|
|
else:
|
|
return node
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
############################
|
|
# Test SimpleTree
|
|
############################
|
|
print("\n\n🌴🌴🌴 Testing SimpleTree 🌴🌴🌴")
|
|
t = SimpleTree('a', [SimpleTree('b', [SimpleTree('d'), SimpleTree('e')]), \
|
|
SimpleTree('c', [SimpleTree('h'), SimpleTree('g')])])
|
|
print(t)
|
|
|
|
|
|
############################
|
|
# Test binary tree
|
|
############################
|
|
print("\n\n🌳🌳🌳 Testing BinaryTree 🌳🌳🌳")
|
|
bt = BinaryTree()
|
|
array1 = [4, 1, 4, 6, 7, 9, 10, 5, 11, 5]
|
|
print(f'\n🟡 Adding {array1} to the tree...')
|
|
for i in array1:
|
|
bt.add_node(i)
|
|
print("🟢 Printing the tree in preorder...")
|
|
bt.print_preorder()
|
|
print(f'\n🟢 Searching for node 5: {bt.search_node(5)}')
|
|
print(f'❌ Searching for node 15: {bt.search_node(15)}')
|
|
print(f'❌ Is root a leaf? {bt.is_leaf()}')
|
|
print(f'🟢 Is root full? {bt.is_full()}')
|
|
print(f'❌ Is the tree balanced? {BinaryTree.is_balanced(bt.root)}')
|
|
print(f'❌ Is the tree a binary search tree? {BinaryTree.is_binary_search_tree(bt.root)}')
|
|
|
|
|
|
|
|
##############################
|
|
# Test binary search tree
|
|
##############################
|
|
print("\n\n🎄🎄🎄 Testing BinarySearchTree 🎄🎄🎄")
|
|
bst = BinarySearchTree()
|
|
array1 = [4, 1, 4, 6, 7, 9, 10, 5, 11, 5]
|
|
print(f'\n🟡 Adding {array1} to the tree...')
|
|
for i in array1:
|
|
bst.add_node(i)
|
|
print("🟢 Printing the tree in preorder:")
|
|
bst.print_preorder()
|
|
print(f'\n🟢 Searching for node 5: {bst.search_node(5)}')
|
|
print(f'❌ Searching for node 15: {bst.search_node(15)}')
|
|
print(f'❌ Is root a leaf? {bst.is_leaf()}')
|
|
print(f'🟢 Is root full? {bst.is_full()}')
|
|
print(f'🟢 Largest node? {bst.largest_node(bst.root)}')
|
|
print(f'🟢 Smallest node? {bst.smallest_node(bst.root)}')
|
|
print(f'❌ Is the tree balanced? {bst.is_balanced(bst.root)}')
|
|
print(f'🟢 Is the tree a binary search tree? {bst.is_binary_search_tree(bst.root)}')
|