-
Notifications
You must be signed in to change notification settings - Fork 0
/
generic.py
160 lines (128 loc) · 4.39 KB
/
generic.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
from abc import ABC, abstractmethod
from typing import Optional, TypeVar, Generic
class Node:
""" Node structure for holding data
key - key of node, **must** be compareable
value - value of node
prev - closest smaller node
nxt - closest bigger node
"""
def __init__(self, key, value=None, prev=None, nxt=None):
if value is None:
value = key
self.key = key
self.value = value
self.prev = prev
self.nxt = nxt
def __repr__(self):
return f"Node( key: {self.key}, value: {self.value} )"
class BinaryNode(Node):
""" Extended structure of node for binary trees
left - left child node
right - right child node
depth - depth of subtree with this node as root
external - flag says if is it **real** node or helper node
"""
def __init__(self, key, value=None, prev=None, nxt=None,
left=None, right=None,
depth: int = 1, external: bool = False):
super().__init__(key, value, prev, nxt)
self.left = left
self.right = right
self.depth = depth
self.external = external
T = TypeVar('T', bound=Node)
class ATree(ABC, Generic[T]):
@abstractmethod
def find(self, key) -> Optional[T]:
""" Find node with given key and return it """
pass
@abstractmethod
def insert(self, key, value) -> None:
""" Insert node with given key and value """
pass
@abstractmethod
def delete(self, key) -> None:
""" Delete node with given key """
pass
@abstractmethod
def findmin(self) -> Optional[T]:
""" Return node with the smallest key or None (tree empty) """
pass
@abstractmethod
def findmax(self) -> Optional[T]:
""" Return node with the biggest key or None (tree empty) """
pass
def validate(self) -> bool:
""" Return true if whole tree is valid (matched all requirements)
Helpfull for debuging and unittests
"""
return True
def _add_node_to_chain(self, node: T,
prev_node: Optional[T], nxt_node: Optional[T]):
node.prev, node.nxt = prev_node, nxt_node
if prev_node is not None:
prev_node.nxt = node
if nxt_node is not None:
nxt_node.prev = node
def _remove_node_from_chain(self, node: T):
prev_node = node.prev
nxt_node = node.nxt
if prev_node is not None:
prev_node.nxt = nxt_node
if nxt_node is not None:
nxt_node.prev = prev_node
BN = TypeVar('BN', bound=BinaryNode)
class ABinarySearchTree(ATree[BN]):
root: BN
def find(self, key) -> Optional[BN]:
def _find(key, node: BN) -> Optional[BN]:
if node.external:
return None
if node.key == key:
return node
elif node.key < key:
return _find(key, node.right)
else:
return _find(key, node.left)
return _find(key, self.root)
def _find_bigger(self, node: BN, key) -> Optional[BN]:
""" Find the node with lowest bigger key """
if node.external:
return None
if key < node.key:
ret = self._find_bigger(node.left, key)
if ret is None:
return node
return ret
else:
return self._find_bigger(node.right, key)
def _find_lower(self, node: BN, key) -> Optional[BN]:
""" Find the node with the largest smaller key """
if node.external:
return None
if key > node.key:
ret = self._find_lower(node.right, key)
if ret is None:
return node
return ret
else:
return self._find_lower(node.left, key)
def findmin(self) -> Optional[BN]:
def _findmin(node):
if node == self.EXTERNAL_NODE:
return None
if node.left == self.EXTERNAL_NODE:
return node
else:
return _findmin(node.left)
return _findmin(self.root)
def findmax(self) -> Optional[BN]:
def _findmax(node):
if node == self.EXTERNAL_NODE:
return None
if node.right == self.EXTERNAL_NODE:
return node
else:
return _findmax(node.right)
return _findmax(self.root)