pkstruct 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. pkstruct/__init__.py +167 -0
  2. pkstruct/graphs/__init__.py +127 -0
  3. pkstruct/graphs/connectivity.py +157 -0
  4. pkstruct/graphs/directed.py +95 -0
  5. pkstruct/graphs/exceptions.py +63 -0
  6. pkstruct/graphs/graph.py +262 -0
  7. pkstruct/graphs/mst.py +118 -0
  8. pkstruct/graphs/scc.py +138 -0
  9. pkstruct/graphs/shortest_path.py +250 -0
  10. pkstruct/graphs/topo_sort.py +108 -0
  11. pkstruct/graphs/traversal.py +175 -0
  12. pkstruct/graphs/visualization.py +90 -0
  13. pkstruct/graphs/weighted.py +37 -0
  14. pkstruct/linear/__init__.py +95 -0
  15. pkstruct/linear/deques/__init__.py +33 -0
  16. pkstruct/linear/deques/deque.py +194 -0
  17. pkstruct/linear/deques/linked_deque.py +198 -0
  18. pkstruct/linear/exceptions.py +26 -0
  19. pkstruct/linear/linked_lists/__init__.py +5 -0
  20. pkstruct/linear/linked_lists/_base.py +608 -0
  21. pkstruct/linear/linked_lists/circular_linked_list.py +230 -0
  22. pkstruct/linear/linked_lists/doubly_linked_list.py +151 -0
  23. pkstruct/linear/linked_lists/nodes.py +68 -0
  24. pkstruct/linear/linked_lists/singly_linked_list.py +136 -0
  25. pkstruct/linear/queues/__init__.py +44 -0
  26. pkstruct/linear/queues/circular_queue.py +258 -0
  27. pkstruct/linear/queues/linked_queue.py +186 -0
  28. pkstruct/linear/queues/priority_queue.py +202 -0
  29. pkstruct/linear/queues/queue.py +174 -0
  30. pkstruct/linear/stacks/__init__.py +38 -0
  31. pkstruct/linear/stacks/array_stack.py +165 -0
  32. pkstruct/linear/stacks/linked_stack.py +168 -0
  33. pkstruct/linear/stacks/stack.py +158 -0
  34. pkstruct/linear/utils/__init__.py +18 -0
  35. pkstruct/linear/utils/benchmark.py +255 -0
  36. pkstruct/linear/utils/debug_tools.py +239 -0
  37. pkstruct/linear/utils/helpers.py +143 -0
  38. pkstruct/linear/utils/iterators.py +148 -0
  39. pkstruct/linear/visualization/__init__.py +0 -0
  40. pkstruct/linear/visualization/ascii_visualizer.py +114 -0
  41. pkstruct/linear/visualization/linked_list_visualizer.py +126 -0
  42. pkstruct/shared/__init__.py +67 -0
  43. pkstruct/shared/benchmarking/__init__.py +78 -0
  44. pkstruct/shared/debugging/__init__.py +69 -0
  45. pkstruct/shared/exceptions/__init__.py +59 -0
  46. pkstruct/shared/serializers/__init__.py +65 -0
  47. pkstruct/shared/threading/__init__.py +43 -0
  48. pkstruct/shared/validators/__init__.py +98 -0
  49. pkstruct/shared/visualization/__init__.py +21 -0
  50. pkstruct/trees/__init__.py +92 -0
  51. pkstruct/trees/avl.py +321 -0
  52. pkstruct/trees/balancing.py +253 -0
  53. pkstruct/trees/bplus.py +425 -0
  54. pkstruct/trees/bst.py +948 -0
  55. pkstruct/trees/btree.py +504 -0
  56. pkstruct/trees/exceptions.py +96 -0
  57. pkstruct/trees/fenwick_tree.py +312 -0
  58. pkstruct/trees/interval_tree.py +541 -0
  59. pkstruct/trees/node.py +356 -0
  60. pkstruct/trees/red_black.py +710 -0
  61. pkstruct/trees/segment_tree.py +398 -0
  62. pkstruct/trees/traversal.py +456 -0
  63. pkstruct/trees/tree_helpers.py +366 -0
  64. pkstruct/trees/utils/__init__.py +15 -0
  65. pkstruct/trees/utils/complexity_helpers.py +231 -0
  66. pkstruct/trees/visualization/__init__.py +0 -0
  67. pkstruct/trees/visualization/ascii_renderer.py +220 -0
  68. pkstruct/trees/visualization/tree_printer.py +129 -0
  69. pkstruct-0.1.0.dist-info/METADATA +482 -0
  70. pkstruct-0.1.0.dist-info/RECORD +72 -0
  71. pkstruct-0.1.0.dist-info/WHEEL +4 -0
  72. pkstruct-0.1.0.dist-info/licenses/LICENSE +21 -0
pkstruct/trees/node.py ADDED
@@ -0,0 +1,356 @@
1
+ """
2
+ pkstruct.trees.node
3
+ ===================
4
+ Reusable node classes for all tree implementations.
5
+
6
+ Inheritance hierarchy::
7
+
8
+ TreeNode
9
+ ├── AVLNode (adds height)
10
+ ├── RBNode (adds color)
11
+ ├── SegmentNode (adds segment metadata)
12
+ └── IntervalNode (adds interval + max_endpoint)
13
+
14
+ BTreeNode (multi-key / multi-child; standalone)
15
+ BPlusNode (leaf-linked variant of BTreeNode)
16
+
17
+ Every node exposes only the fields it needs; fields not relevant to a
18
+ concrete subclass are never allocated.
19
+ """
20
+
21
+ from __future__ import annotations
22
+
23
+ from typing import Any, Generic, TypeVar
24
+
25
+ __all__ = [
26
+ "TreeNode",
27
+ "AVLNode",
28
+ "RBNode",
29
+ "BTreeNode",
30
+ "BPlusNode",
31
+ "SegmentNode",
32
+ "IntervalNode",
33
+ ]
34
+
35
+ KT = TypeVar("KT") # key type
36
+ VT = TypeVar("VT") # value type
37
+
38
+ # ---------------------------------------------------------------------------
39
+ # Sentinel colours used by RBNode (module-level so they are importable)
40
+ # ---------------------------------------------------------------------------
41
+ RED: int = 0
42
+ BLACK: int = 1
43
+
44
+
45
+ class TreeNode(Generic[KT, VT]):
46
+ """
47
+ Base binary-tree node.
48
+
49
+ Attributes
50
+ ----------
51
+ key:
52
+ Comparable key used for ordering.
53
+ value:
54
+ Arbitrary payload; defaults to *None*.
55
+ left:
56
+ Left child or *None*.
57
+ right:
58
+ Right child or *None*.
59
+ parent:
60
+ Parent node or *None* (root).
61
+ """
62
+
63
+ __slots__ = ("key", "value", "left", "right", "parent")
64
+
65
+ def __init__(
66
+ self,
67
+ key: KT,
68
+ value: VT | None = None,
69
+ *,
70
+ left: TreeNode[KT, VT] | None = None,
71
+ right: TreeNode[KT, VT] | None = None,
72
+ parent: TreeNode[KT, VT] | None = None,
73
+ ) -> None:
74
+ self.key: KT = key
75
+ self.value: VT | None = value
76
+ self.left: TreeNode[KT, VT] | None = left
77
+ self.right: TreeNode[KT, VT] | None = right
78
+ self.parent: TreeNode[KT, VT] | None = parent
79
+
80
+ # ------------------------------------------------------------------
81
+ # Helpers
82
+ # ------------------------------------------------------------------
83
+
84
+ def is_leaf(self) -> bool:
85
+ """Return *True* when the node has no children."""
86
+ return self.left is None and self.right is None
87
+
88
+ def is_root(self) -> bool:
89
+ """Return *True* when the node has no parent."""
90
+ return self.parent is None
91
+
92
+ def is_left_child(self) -> bool:
93
+ """Return *True* when this node is the left child of its parent."""
94
+ return self.parent is not None and self.parent.left is self
95
+
96
+ def is_right_child(self) -> bool:
97
+ """Return *True* when this node is the right child of its parent."""
98
+ return self.parent is not None and self.parent.right is self
99
+
100
+ def sibling(self) -> TreeNode[KT, VT] | None:
101
+ """Return the sibling node, or *None* if no parent."""
102
+ if self.parent is None:
103
+ return None
104
+ return self.parent.right if self.is_left_child() else self.parent.left
105
+
106
+ def __repr__(self) -> str: # pragma: no cover
107
+ return f"{type(self).__name__}(key={self.key!r}, value={self.value!r})"
108
+
109
+
110
+ # ---------------------------------------------------------------------------
111
+ # AVL Node
112
+ # ---------------------------------------------------------------------------
113
+
114
+
115
+ class AVLNode(TreeNode[KT, VT]):
116
+ """
117
+ AVL-tree node with *height* field.
118
+
119
+ The height of a leaf is **1**; *None* sentinel nodes have height **0**.
120
+
121
+ Attributes
122
+ ----------
123
+ height:
124
+ Height of the sub-tree rooted at this node.
125
+ """
126
+
127
+ __slots__ = ("height",)
128
+
129
+ def __init__(
130
+ self,
131
+ key: KT,
132
+ value: VT | None = None,
133
+ *,
134
+ left: AVLNode[KT, VT] | None = None,
135
+ right: AVLNode[KT, VT] | None = None,
136
+ parent: AVLNode[KT, VT] | None = None,
137
+ ) -> None:
138
+ super().__init__(key, value, left=left, right=right, parent=parent)
139
+ self.height: int = 1
140
+
141
+
142
+ # ---------------------------------------------------------------------------
143
+ # Red-Black Node
144
+ # ---------------------------------------------------------------------------
145
+
146
+
147
+ class RBNode(TreeNode[KT, VT]):
148
+ """
149
+ Red-black tree node with *color* field.
150
+
151
+ Attributes
152
+ ----------
153
+ color:
154
+ Either :data:`RED` (0) or :data:`BLACK` (1).
155
+ """
156
+
157
+ __slots__ = ("color",)
158
+
159
+ def __init__(
160
+ self,
161
+ key: KT,
162
+ value: VT | None = None,
163
+ *,
164
+ color: int = RED,
165
+ left: RBNode[KT, VT] | None = None,
166
+ right: RBNode[KT, VT] | None = None,
167
+ parent: RBNode[KT, VT] | None = None,
168
+ ) -> None:
169
+ super().__init__(key, value, left=left, right=right, parent=parent)
170
+ self.color: int = color
171
+
172
+ def is_red(self) -> bool:
173
+ """Return *True* when the node is red."""
174
+ return self.color == RED
175
+
176
+ def is_black(self) -> bool:
177
+ """Return *True* when the node is black."""
178
+ return self.color == BLACK
179
+
180
+
181
+ # ---------------------------------------------------------------------------
182
+ # B-Tree Node
183
+ # ---------------------------------------------------------------------------
184
+
185
+
186
+ class BTreeNode(Generic[KT, VT]):
187
+ """
188
+ Multi-key / multi-child node used by :class:`~pkstruct.trees.btree.BTree`.
189
+
190
+ Attributes
191
+ ----------
192
+ keys:
193
+ Ordered list of keys stored in this node.
194
+ values:
195
+ Parallel list of values; ``values[i]`` corresponds to ``keys[i]``.
196
+ children:
197
+ Child nodes; an internal node with *k* keys has *k+1* children.
198
+ Leaf nodes have an empty children list.
199
+ parent:
200
+ Parent node or *None* (root).
201
+ """
202
+
203
+ __slots__ = ("keys", "values", "children", "parent")
204
+
205
+ def __init__(self) -> None:
206
+ self.keys: list[KT] = []
207
+ self.values: list[VT | None] = []
208
+ self.children: list[BTreeNode[KT, VT]] = []
209
+ self.parent: BTreeNode[KT, VT] | None = None
210
+
211
+ def is_leaf(self) -> bool:
212
+ """Return *True* when this node has no children."""
213
+ return len(self.children) == 0
214
+
215
+ def __repr__(self) -> str: # pragma: no cover
216
+ return f"BTreeNode(keys={self.keys!r})"
217
+
218
+
219
+ # ---------------------------------------------------------------------------
220
+ # B+ Tree Node
221
+ # ---------------------------------------------------------------------------
222
+
223
+
224
+ class BPlusNode(Generic[KT, VT]):
225
+ """
226
+ Node for :class:`~pkstruct.trees.bplus.BPlusTree`.
227
+
228
+ Leaf nodes carry ``(key, value)`` pairs and a ``next_leaf`` pointer.
229
+ Internal nodes carry separator keys and child pointers.
230
+
231
+ Attributes
232
+ ----------
233
+ keys:
234
+ Ordered list of keys.
235
+ values:
236
+ Values stored only in leaf nodes.
237
+ children:
238
+ Child pointers (internal nodes only).
239
+ parent:
240
+ Parent node or *None*.
241
+ next_leaf:
242
+ Pointer to the next leaf (leaf nodes only); forms a linked list.
243
+ is_leaf:
244
+ *True* when this is a leaf node.
245
+ """
246
+
247
+ __slots__ = ("keys", "values", "children", "parent", "next_leaf", "is_leaf")
248
+
249
+ def __init__(self, *, is_leaf: bool = False) -> None:
250
+ self.keys: list[KT] = []
251
+ self.values: list[VT | None] = [] # leaf only
252
+ self.children: list[BPlusNode[KT, VT]] = [] # internal only
253
+ self.parent: BPlusNode[KT, VT] | None = None
254
+ self.next_leaf: BPlusNode[KT, VT] | None = None # leaf only
255
+ self.is_leaf: bool = is_leaf
256
+
257
+ def __repr__(self) -> str: # pragma: no cover
258
+ return f"BPlusNode(keys={self.keys!r}, leaf={self.is_leaf})"
259
+
260
+
261
+ # ---------------------------------------------------------------------------
262
+ # Segment Tree Node
263
+ # ---------------------------------------------------------------------------
264
+
265
+
266
+ class SegmentNode:
267
+ """
268
+ Node for :class:`~pkstruct.trees.segment_tree.SegmentTree`.
269
+
270
+ The tree is stored as a flat array (1-indexed), so this class is used
271
+ only when a pointer-based implementation is preferred.
272
+
273
+ Attributes
274
+ ----------
275
+ start:
276
+ Left boundary of the segment (inclusive).
277
+ end:
278
+ Right boundary of the segment (inclusive).
279
+ value:
280
+ Aggregated value (sum / min / max / …) of the segment.
281
+ lazy:
282
+ Pending lazy-propagation value; *None* means no pending update.
283
+ left:
284
+ Left child segment node.
285
+ right:
286
+ Right child segment node.
287
+ """
288
+
289
+ __slots__ = ("start", "end", "value", "lazy", "left", "right")
290
+
291
+ def __init__(
292
+ self,
293
+ start: int,
294
+ end: int,
295
+ value: Any = 0,
296
+ lazy: Any | None = None,
297
+ ) -> None:
298
+ self.start: int = start
299
+ self.end: int = end
300
+ self.value: Any = value
301
+ self.lazy: Any | None = lazy
302
+ self.left: SegmentNode | None = None
303
+ self.right: SegmentNode | None = None
304
+
305
+ def __repr__(self) -> str: # pragma: no cover
306
+ return (
307
+ f"SegmentNode([{self.start},{self.end}], "
308
+ f"value={self.value!r}, lazy={self.lazy!r})"
309
+ )
310
+
311
+
312
+ # ---------------------------------------------------------------------------
313
+ # Interval Tree Node
314
+ # ---------------------------------------------------------------------------
315
+
316
+
317
+ class IntervalNode(TreeNode[KT, VT]):
318
+ """
319
+ Augmented BST node used by :class:`~pkstruct.trees.interval_tree.IntervalTree`.
320
+
321
+ Each node represents a half-open or closed interval ``[lo, hi]``.
322
+ The ``max_endpoint`` field stores the maximum ``hi`` value in the
323
+ sub-tree rooted at this node, enabling O(log n) overlap queries.
324
+
325
+ Attributes
326
+ ----------
327
+ lo:
328
+ Left endpoint of the interval (used as the BST key).
329
+ hi:
330
+ Right endpoint of the interval.
331
+ max_endpoint:
332
+ Maximum ``hi`` value in the sub-tree rooted here.
333
+ """
334
+
335
+ __slots__ = ("lo", "hi", "max_endpoint")
336
+
337
+ def __init__(
338
+ self,
339
+ lo: KT,
340
+ hi: KT,
341
+ value: VT | None = None,
342
+ *,
343
+ left: IntervalNode[KT, VT] | None = None,
344
+ right: IntervalNode[KT, VT] | None = None,
345
+ parent: IntervalNode[KT, VT] | None = None,
346
+ ) -> None:
347
+ super().__init__(lo, value, left=left, right=right, parent=parent)
348
+ self.lo: KT = lo
349
+ self.hi: KT = hi
350
+ self.max_endpoint: KT = hi
351
+
352
+ def __repr__(self) -> str: # pragma: no cover
353
+ return (
354
+ f"IntervalNode([{self.lo!r}, {self.hi!r}], "
355
+ f"max={self.max_endpoint!r})"
356
+ )