added some recursive datastructures
This commit is contained in:
62
recursion/recursive_datastructure/solution/lists.py
Normal file
62
recursion/recursive_datastructure/solution/lists.py
Normal file
@ -0,0 +1,62 @@
|
||||
from dataclasses import dataclass
|
||||
from typing import Iterator, Optional
|
||||
|
||||
@dataclass
|
||||
class Node[T]:
|
||||
value: T
|
||||
next_node: Optional['Node[T]']
|
||||
|
||||
|
||||
@dataclass
|
||||
class LinkedList[T]:
|
||||
|
||||
def __post_init__(self):
|
||||
self.__head: Optional[Node[T]] = None
|
||||
self.__length = 0
|
||||
|
||||
def __eq__(self, other: 'LinkedList[T]') -> bool:
|
||||
if len(self) != len(other):
|
||||
return False
|
||||
for i in range(0, len(self)):
|
||||
if self[i] != self[i]:
|
||||
return False
|
||||
return True
|
||||
|
||||
def __iter__(self) -> Iterator[T]:
|
||||
node = self.__head
|
||||
while node:
|
||||
yield node.value
|
||||
node = node.next_node
|
||||
|
||||
def append(self, value: T):
|
||||
if not self.__head:
|
||||
self.__head = Node(value, None)
|
||||
else:
|
||||
node = self.__head
|
||||
while node.next_node:
|
||||
node = node.next_node
|
||||
node.next_node = Node(value, None)
|
||||
self.__length += 1
|
||||
|
||||
def remove(self, value: T):
|
||||
if self.__head and self.__head.value == value:
|
||||
self.__head = self.__head.next_node
|
||||
self.__length -= 1
|
||||
elif self.__head:
|
||||
node = self.__head
|
||||
while node.next_node and node.next_node.value != value:
|
||||
node = node.next_node
|
||||
if node.next_node and node.next_node.value == value:
|
||||
node.next_node = node.next_node.next_node
|
||||
self.__length -= 1
|
||||
|
||||
def __len__(self) -> int:
|
||||
return self.__length
|
||||
|
||||
def __getitem__(self, index: int) -> T:
|
||||
if index >= len(self):
|
||||
raise IndexError
|
||||
node = self.__head
|
||||
for _ in range(0, index):
|
||||
node = node.next_node
|
||||
return node.value
|
45
recursion/recursive_datastructure/solution/search_trees.py
Normal file
45
recursion/recursive_datastructure/solution/search_trees.py
Normal file
@ -0,0 +1,45 @@
|
||||
from typing import Iterator, Optional
|
||||
from trees import Node, traverse
|
||||
from dataclasses import InitVar, dataclass
|
||||
|
||||
@dataclass
|
||||
class BinarySearchTree[T]:
|
||||
|
||||
def __post_init__(self):
|
||||
self.__root: Optional[Node[T]] = None
|
||||
|
||||
|
||||
def insert(self, value: T):
|
||||
prev = None
|
||||
curr = self.__root
|
||||
while curr:
|
||||
prev = curr
|
||||
if curr.value > value:
|
||||
curr = curr.left
|
||||
else:
|
||||
curr = curr.right
|
||||
if prev is None:
|
||||
self.__root = Node(value, None, None)
|
||||
elif value < prev.value:
|
||||
prev.left = Node(value, None, None)
|
||||
else:
|
||||
prev.right = Node(value, None, None)
|
||||
|
||||
def __delete(prev: Node[T], to_delete: Node[T]) -> Node[T]:
|
||||
# TODO: implement
|
||||
pass
|
||||
|
||||
def remove(self, value: T):
|
||||
prev = None
|
||||
curr = self.__root
|
||||
while curr:
|
||||
prev = curr
|
||||
if curr.value > value:
|
||||
curr = curr.left
|
||||
elif curr.value < value:
|
||||
curr = curr.right
|
||||
else:
|
||||
curr = self.__delete(prev, curr)
|
||||
|
||||
def __iter__(self) -> Iterator[T]:
|
||||
yield from traverse(self.__root)
|
77
recursion/recursive_datastructure/solution/test_lists.py
Normal file
77
recursion/recursive_datastructure/solution/test_lists.py
Normal file
@ -0,0 +1,77 @@
|
||||
from lists import LinkedList
|
||||
|
||||
def test_append():
|
||||
lst = LinkedList[int]()
|
||||
lst.append(1)
|
||||
lst.append(2)
|
||||
lst.append(3)
|
||||
lst.append(4)
|
||||
lst2 = LinkedList[int]()
|
||||
lst2.append(1)
|
||||
lst2.append(2)
|
||||
lst2.append(3)
|
||||
lst2.append(4)
|
||||
assert lst == lst2
|
||||
|
||||
def test_remove():
|
||||
lst = LinkedList[int]()
|
||||
lst.remove(0)
|
||||
lst.append(1)
|
||||
lst.append(2)
|
||||
lst.append(3)
|
||||
lst.append(4)
|
||||
lst.remove(2)
|
||||
lst.remove(5)
|
||||
lst2 = LinkedList[int]()
|
||||
lst2.append(1)
|
||||
lst2.append(3)
|
||||
lst2.append(4)
|
||||
assert lst == lst2
|
||||
|
||||
def test_length():
|
||||
lst = LinkedList[int]()
|
||||
lst.append(0)
|
||||
lst.append(1)
|
||||
lst.append(2)
|
||||
lst.append(3)
|
||||
lst.append(4)
|
||||
assert len(lst) == 5
|
||||
lst.remove(0)
|
||||
assert len(lst) == 4
|
||||
lst.remove(2)
|
||||
assert len(lst) == 3
|
||||
lst.remove(1)
|
||||
assert len(lst) == 2
|
||||
lst.remove(3)
|
||||
assert len(lst) == 1
|
||||
lst.remove(4)
|
||||
assert len(lst) == 0
|
||||
lst.remove(4)
|
||||
lst.remove(5)
|
||||
assert len(lst) == 0
|
||||
|
||||
|
||||
def test_index():
|
||||
lst = LinkedList[int]()
|
||||
lst.append(0)
|
||||
lst.append(1)
|
||||
lst.append(2)
|
||||
lst.append(3)
|
||||
lst.append(4)
|
||||
assert lst[0] == 0
|
||||
assert lst[1] == 1
|
||||
assert lst[2] == 2
|
||||
assert lst[3] == 3
|
||||
assert lst[4] == 4
|
||||
|
||||
def test_iter():
|
||||
lst = LinkedList[int]()
|
||||
lst.append(0)
|
||||
lst.append(1)
|
||||
lst.append(2)
|
||||
lst.append(3)
|
||||
lst.append(4)
|
||||
j = 0
|
||||
for i in iter(lst):
|
||||
assert i == j
|
||||
j += 1
|
@ -0,0 +1,24 @@
|
||||
from search_trees import BinarySearchTree
|
||||
from random import randint as random
|
||||
|
||||
MAX= 1000
|
||||
MIN = 0
|
||||
LENGTH = 100
|
||||
|
||||
def test_insert():
|
||||
nums = [random(MIN, MAX) for _ in range(0, LENGTH)]
|
||||
bst = BinarySearchTree()
|
||||
for num in nums:
|
||||
bst.insert(num)
|
||||
assert list(iter(bst)) == sorted(nums)
|
||||
|
||||
def test_remove():
|
||||
nums = {random(MIN, MAX) for _ in range(0, LENGTH)}
|
||||
fil = {random(MIN, MAX) for _ in range(0, LENGTH // 4)}
|
||||
bst = BinarySearchTree()
|
||||
for num in nums:
|
||||
bst.insert(num)
|
||||
for num in fil:
|
||||
bst.remove(num)
|
||||
|
||||
assert list(iter(bst)) == sorted(filter(lambda x: x not in fil, nums))
|
13
recursion/recursive_datastructure/solution/test_trees.py
Normal file
13
recursion/recursive_datastructure/solution/test_trees.py
Normal file
@ -0,0 +1,13 @@
|
||||
from trees import Node, traverse, TraversalType
|
||||
|
||||
|
||||
def test_traverse():
|
||||
tree = Node(1, Node(2, Node(3, None, None), Node(4, Node(
|
||||
5, None, None), None)), Node(6, Node(7, None, None), Node(8, None, None)))
|
||||
|
||||
assert ", ".join(map(lambda x: str(x), traverse(tree))
|
||||
) == "3, 2, 5, 4, 1, 7, 6, 8"
|
||||
assert ", ".join(map(lambda x: str(x), traverse(
|
||||
tree, TraversalType.PREORDER))) == "1, 2, 3, 4, 5, 6, 7, 8"
|
||||
assert ", ".join(map(lambda x: str(x), traverse(
|
||||
tree, TraversalType.POSTORDER))) == "3, 5, 4, 2, 7, 8, 6, 1"
|
33
recursion/recursive_datastructure/solution/trees.py
Normal file
33
recursion/recursive_datastructure/solution/trees.py
Normal file
@ -0,0 +1,33 @@
|
||||
from dataclasses import dataclass
|
||||
from enum import Enum, auto
|
||||
from typing import Iterator, Optional
|
||||
|
||||
|
||||
@dataclass
|
||||
class Node[T]:
|
||||
value: T
|
||||
left: Optional['Node[T]']
|
||||
right: Optional['Node[T]']
|
||||
|
||||
|
||||
type BinaryTree[T] = Optional[Node[T]]
|
||||
|
||||
class TraversalType(Enum):
|
||||
INORDER, POSTORDER, PREORDER = auto(), auto(), auto()
|
||||
|
||||
def traverse[T](tree: BinaryTree[T], order: TraversalType = TraversalType.INORDER) -> Iterator[T]:
|
||||
match (tree, order):
|
||||
case (Node(value, left, right), TraversalType.INORDER):
|
||||
yield from traverse(left, order)
|
||||
yield value
|
||||
yield from traverse(right, order)
|
||||
case (Node(value, left, right), TraversalType.POSTORDER):
|
||||
yield from traverse(left, order)
|
||||
yield from traverse(right, order)
|
||||
yield value
|
||||
case (Node(value, left, right), TraversalType.PREORDER):
|
||||
yield value
|
||||
yield from traverse(left, order)
|
||||
yield from traverse(right, order)
|
||||
case _:
|
||||
return
|
Reference in New Issue
Block a user