Add homework
This commit is contained in:
@@ -0,0 +1,49 @@
|
|||||||
|
# Also do the 2026.05.06 homework
|
||||||
|
#
|
||||||
|
# Implement insertion, removal and search in a binary search tree.
|
||||||
|
# Properties of binary search trees:
|
||||||
|
# - Each node has at most two children
|
||||||
|
# - The left subtree of a node contains only nodes with values less than the node's value
|
||||||
|
# - The right subtree of a node contains only nodes with values greater than the node's value
|
||||||
|
#
|
||||||
|
# Example of what such a tree would look like:
|
||||||
|
# 10
|
||||||
|
# / \
|
||||||
|
# 5 15
|
||||||
|
# / \ \
|
||||||
|
# 3 7 20
|
||||||
|
#
|
||||||
|
# Example of an *invalid* tree:
|
||||||
|
# 10
|
||||||
|
# / \
|
||||||
|
# 5 15
|
||||||
|
# / \ \
|
||||||
|
# 3 7 20
|
||||||
|
# \
|
||||||
|
# 12
|
||||||
|
#
|
||||||
|
# Don't worry about balancing the tree for now, we will cover that later
|
||||||
|
|
||||||
|
|
||||||
|
class Node:
|
||||||
|
def __init__(self, value):
|
||||||
|
self.value = value
|
||||||
|
self.left = None
|
||||||
|
self.right = None
|
||||||
|
|
||||||
|
|
||||||
|
class BinarySearchTree:
|
||||||
|
def __init__(self):
|
||||||
|
self.root = None
|
||||||
|
|
||||||
|
def insert(self, value):
|
||||||
|
# TODO
|
||||||
|
pass
|
||||||
|
|
||||||
|
def remove(self, value):
|
||||||
|
# TODO
|
||||||
|
pass
|
||||||
|
|
||||||
|
def search(self, value):
|
||||||
|
# TODO
|
||||||
|
pass
|
||||||
|
|||||||
121
notes-and-examples/2026.05.13/trees.py
Normal file
121
notes-and-examples/2026.05.13/trees.py
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
# Example: expression tree + evaluation
|
||||||
|
|
||||||
|
from enum import Enum
|
||||||
|
|
||||||
|
|
||||||
|
class TokenType(Enum):
|
||||||
|
NUMBER = 1
|
||||||
|
OPERATOR = 2
|
||||||
|
|
||||||
|
|
||||||
|
# either store an operator (+, -, *, /) or a number
|
||||||
|
class Token:
|
||||||
|
def __init__(self, type: TokenType, value: str):
|
||||||
|
self.type = type
|
||||||
|
self.value = value
|
||||||
|
|
||||||
|
|
||||||
|
# each individual element in the tree
|
||||||
|
class Node:
|
||||||
|
left = None
|
||||||
|
right = None
|
||||||
|
|
||||||
|
def __init__(self, token: Token, left=None, right=None):
|
||||||
|
self.token = token
|
||||||
|
self.left = left
|
||||||
|
self.right = right
|
||||||
|
|
||||||
|
|
||||||
|
# holder for the tree
|
||||||
|
class ExpressionTree:
|
||||||
|
def __init__(self, root: Node | None):
|
||||||
|
self.root = root
|
||||||
|
|
||||||
|
|
||||||
|
def evaluate(tree: ExpressionTree) -> int:
|
||||||
|
return _evaluate(tree.root)
|
||||||
|
|
||||||
|
|
||||||
|
# evaluate a tree recursively starting from the node
|
||||||
|
def _evaluate(node: Node | None) -> int:
|
||||||
|
if node is None:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
if node.token.type == TokenType.NUMBER:
|
||||||
|
return int(node.token.value)
|
||||||
|
|
||||||
|
elif node.token.type == TokenType.OPERATOR:
|
||||||
|
if node.left is None or node.right is None:
|
||||||
|
raise ValueError(f"Operator {node.token.value} requires two operands")
|
||||||
|
|
||||||
|
left = _evaluate(node.left)
|
||||||
|
right = _evaluate(node.right)
|
||||||
|
|
||||||
|
if node.token.value == "+":
|
||||||
|
return left + right
|
||||||
|
elif node.token.value == "-":
|
||||||
|
return left - right
|
||||||
|
elif node.token.value == "*":
|
||||||
|
return left * right
|
||||||
|
elif node.token.value == "/":
|
||||||
|
return left // right
|
||||||
|
|
||||||
|
raise ValueError(f"Unknown operator: {node.token.value}")
|
||||||
|
|
||||||
|
|
||||||
|
# test cases
|
||||||
|
test_cases = [
|
||||||
|
(ExpressionTree(Node(Token(TokenType.NUMBER, "5"))), 5),
|
||||||
|
(
|
||||||
|
ExpressionTree(
|
||||||
|
Node(
|
||||||
|
Token(TokenType.OPERATOR, "+"),
|
||||||
|
Node(Token(TokenType.NUMBER, "3")),
|
||||||
|
Node(Token(TokenType.NUMBER, "2")),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
5,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
ExpressionTree(
|
||||||
|
Node(
|
||||||
|
Token(TokenType.OPERATOR, "+"),
|
||||||
|
Node(Token(TokenType.NUMBER, "3")),
|
||||||
|
Node(
|
||||||
|
Token(TokenType.OPERATOR, "*"),
|
||||||
|
Node(Token(TokenType.NUMBER, "2")),
|
||||||
|
Node(Token(TokenType.NUMBER, "3")),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
9,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
ExpressionTree(
|
||||||
|
Node(
|
||||||
|
Token(TokenType.OPERATOR, "+"),
|
||||||
|
Node(
|
||||||
|
Token(TokenType.OPERATOR, "-"),
|
||||||
|
Node(Token(TokenType.NUMBER, "3")),
|
||||||
|
Node(Token(TokenType.NUMBER, "2")),
|
||||||
|
),
|
||||||
|
Node(
|
||||||
|
Token(TokenType.OPERATOR, "*"),
|
||||||
|
Node(Token(TokenType.NUMBER, "2")),
|
||||||
|
Node(Token(TokenType.NUMBER, "3")),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
7,
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def test_evaluate() -> None:
|
||||||
|
for tree, expected in test_cases:
|
||||||
|
evaluation = evaluate(tree) == expected
|
||||||
|
print(f"Test case: evaluate({tree}) == {expected} -> {evaluation}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
test_evaluate()
|
||||||
Reference in New Issue
Block a user