mirror of
https://github.com/autistic-symposium/master-algorithms-py.git
synced 2025-04-29 20:26:07 -04:00
Add trees, binary trees, bst, transversals (#34)
This commit is contained in:
parent
5af08f7498
commit
f3ee2cdf52
@ -14,9 +14,9 @@
|
|||||||
<br>
|
<br>
|
||||||
|
|
||||||
* **[📖 my book on algorithms and data structure in python (2014)](book)**:
|
* **[📖 my book on algorithms and data structure in python (2014)](book)**:
|
||||||
- **one of the first ever publication to solve classic computer science algorithm and data structure problems in python.**
|
- **one of the first-ever publications to solve classic computer science algorithm and data structure problems in python.**
|
||||||
- **[it was published by hanbit media in 2014](https://www.hanbit.co.kr/store/books/look.php?p_code=B8465804191)**.
|
- **[it was published by hanbit media in 2014](https://www.hanbit.co.kr/store/books/look.php?p_code=B8465804191)**.
|
||||||
- **[as of today, has 4.6/5 stars and 33 reviews](https://www.hanbit.co.kr/store/books/look.php?p_code=B8465804191)**.
|
- **[as of today, it has 4.6/5 stars and 33 reviews](https://www.hanbit.co.kr/store/books/look.php?p_code=B8465804191)**.
|
||||||
- **[this book as a reference for a CMU computer science class](https://www.andrew.cmu.edu/user/ramesh/teaching/course/48784.pdf)**.
|
- **[this book as a reference for a CMU computer science class](https://www.andrew.cmu.edu/user/ramesh/teaching/course/48784.pdf)**.
|
||||||
- **[here is a pic when this repo used to have 600+ stars and 300 forks (before 💩 happened 😞)](book/600_stars.png)**.
|
- **[here is a pic when this repo used to have 600+ stars and 300 forks (before 💩 happened 😞)](book/600_stars.png)**.
|
||||||
|
|
||||||
@ -47,6 +47,7 @@
|
|||||||
* 𝟙𝟘𝟘𝟙. **[sorting and searching](sorting_and_searching)**
|
* 𝟙𝟘𝟘𝟙. **[sorting and searching](sorting_and_searching)**
|
||||||
* 𝟙𝟘𝟙𝟘. **[concurrency](concurrency)**
|
* 𝟙𝟘𝟙𝟘. **[concurrency](concurrency)**
|
||||||
* 𝟙𝟘𝟙𝟙. **[trees and graphs](trees_and_graphs/)**
|
* 𝟙𝟘𝟙𝟙. **[trees and graphs](trees_and_graphs/)**
|
||||||
|
- [trees, nodes, binary trees, binary search, trees](trees_and_graphs/Trees.py)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -19,7 +19,7 @@ class Node(object):
|
|||||||
new_node = Node(value)
|
new_node = Node(value)
|
||||||
|
|
||||||
if not self.item:
|
if not self.item:
|
||||||
self.item = new_node
|
self.item = new_node.value
|
||||||
|
|
||||||
else:
|
else:
|
||||||
if value > self.item:
|
if value > self.item:
|
||||||
|
@ -37,7 +37,7 @@ def isBST_other_method(node, max_node=None, min_node=None):
|
|||||||
|
|
||||||
if node.right:
|
if node.right:
|
||||||
if node.right.item < node.item or node.right.item < min_node:
|
if node.right.item < node.item or node.right.item < min_node:
|
||||||
rihjt = False
|
right = False
|
||||||
else:
|
else:
|
||||||
min_node = node.item
|
min_node = node.item
|
||||||
right = isBST(node.right, max_node, min_node)
|
right = isBST(node.right, max_node, min_node)
|
||||||
|
298
trees_and_graphs/Trees.py
Normal file
298
trees_and_graphs/Trees.py
Normal file
@ -0,0 +1,298 @@
|
|||||||
|
#!/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)}')
|
||||||
|
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user