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
@@ -0,0 +1,95 @@
1
+ """
2
+ pkstruct.linear
3
+ ===============
4
+
5
+ Linear data structures module for the pkstruct ecosystem.
6
+
7
+ Provides production-grade implementations of linked lists, stacks, queues,
8
+ and deques with full thread safety, debug tracing, benchmarking, and
9
+ ASCII visualization support.
10
+
11
+ Classes
12
+ -------
13
+ SinglyLinkedList
14
+ A singly linked list with forward traversal.
15
+ DoublyLinkedList
16
+ A doubly linked list with both forward and backward traversal.
17
+ CircularLinkedList
18
+ A circular linked list maintaining the circular invariant.
19
+ ArrayStack
20
+ LIFO stack backed by a dynamic array.
21
+ LinkedStack
22
+ LIFO stack backed by ``SinglyLinkedList``.
23
+ LinkedQueue
24
+ FIFO queue backed by ``SinglyLinkedList``.
25
+ CircularQueue
26
+ Fixed-capacity FIFO queue backed by a ring buffer.
27
+ PriorityQueue
28
+ Min-heap priority queue.
29
+ LinkedDeque
30
+ Double-ended queue backed by ``DoublyLinkedList``.
31
+
32
+ Exceptions
33
+ ----------
34
+ PkstructError, ValidationError, IndexOutOfRangeError, ValueNotFoundError,
35
+ EmptyStructureError, SerializationError, ConcurrencyError, InvalidRangeError,
36
+ QueueFullError
37
+
38
+ Example
39
+ -------
40
+ >>> from pkstruct.linear import SinglyLinkedList, LinkedStack
41
+ >>> ll = SinglyLinkedList()
42
+ >>> ll.insert(10)
43
+ >>> s = LinkedStack([1, 2, 3])
44
+ >>> s.pop()
45
+ 3
46
+ """
47
+
48
+ from pkstruct.linear.deques.linked_deque import LinkedDeque
49
+ from pkstruct.linear.exceptions import (
50
+ ConcurrencyError,
51
+ EmptyStructureError,
52
+ IndexOutOfRangeError,
53
+ InvalidRangeError,
54
+ PkstructError,
55
+ SerializationError,
56
+ ValidationError,
57
+ ValueNotFoundError,
58
+ )
59
+ from pkstruct.linear.linked_lists.circular_linked_list import CircularLinkedList
60
+ from pkstruct.linear.linked_lists.doubly_linked_list import DoublyLinkedList
61
+ from pkstruct.linear.linked_lists.singly_linked_list import SinglyLinkedList
62
+ from pkstruct.linear.queues.circular_queue import CircularQueue, QueueFullError
63
+ from pkstruct.linear.queues.linked_queue import LinkedQueue
64
+ from pkstruct.linear.queues.priority_queue import PriorityQueue
65
+ from pkstruct.linear.stacks.array_stack import ArrayStack
66
+ from pkstruct.linear.stacks.linked_stack import LinkedStack
67
+
68
+ __all__ = [
69
+ # Linked list classes
70
+ "SinglyLinkedList",
71
+ "DoublyLinkedList",
72
+ "CircularLinkedList",
73
+ # Stack classes
74
+ "ArrayStack",
75
+ "LinkedStack",
76
+ # Queue classes
77
+ "LinkedQueue",
78
+ "CircularQueue",
79
+ "PriorityQueue",
80
+ # Deque classes
81
+ "LinkedDeque",
82
+ # Exceptions
83
+ "PkstructError",
84
+ "ValidationError",
85
+ "IndexOutOfRangeError",
86
+ "ValueNotFoundError",
87
+ "EmptyStructureError",
88
+ "SerializationError",
89
+ "ConcurrencyError",
90
+ "InvalidRangeError",
91
+ "QueueFullError",
92
+ ]
93
+
94
+ __version__ = "0.1.0"
95
+ __author__ = "pkstruct contributors"
@@ -0,0 +1,33 @@
1
+ """
2
+ pkstruct.linear.deques
3
+ ======================
4
+
5
+ Double-ended queue (deque) data structures for the pkstruct ecosystem.
6
+
7
+ Provides a concrete doubly-linked-list-backed deque and a shared abstract base.
8
+
9
+ Classes
10
+ -------
11
+ Deque
12
+ Abstract base class defining the deque interface.
13
+ LinkedDeque
14
+ Deque backed by ``DoublyLinkedList`` (O(1) at both ends, thread-safe).
15
+
16
+ Example
17
+ -------
18
+ >>> from pkstruct.linear.deques import LinkedDeque
19
+ >>> d = LinkedDeque([1, 2, 3])
20
+ >>> d.append(0, side="left")
21
+ >>> d.append(4, side="right")
22
+ >>> list(d)
23
+ [0, 1, 2, 3, 4]
24
+ """
25
+
26
+ from pkstruct.linear.deques.deque import Deque
27
+ from pkstruct.linear.deques.linked_deque import LinkedDeque
28
+
29
+ __all__ = [
30
+ # Deque classes
31
+ "Deque",
32
+ "LinkedDeque",
33
+ ]
@@ -0,0 +1,194 @@
1
+ """
2
+ pkstruct.linear.deques.deque
3
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4
+ Abstract base class for all double-ended queue implementations.
5
+
6
+ Provides a formal interface contract. Every concrete deque in ``pkstruct``
7
+ derives from this class and implements all abstract methods.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ from abc import ABC, abstractmethod
13
+ from collections.abc import Iterator
14
+ from typing import Generic, Literal, TypeVar
15
+
16
+ T = TypeVar("T")
17
+
18
+ _Side = Literal["left", "right"]
19
+
20
+
21
+ class Deque(ABC, Generic[T]):
22
+ """
23
+ Abstract base class for double-ended queue (deque) structures.
24
+
25
+ Subclasses must implement all abstract methods. The interface supports
26
+ O(1) append and pop at both ends, plus rotation and reversal.
27
+
28
+ Parameters
29
+ ----------
30
+ No parameters required at the abstract level.
31
+ """
32
+
33
+ __slots__ = ()
34
+
35
+ # ------------------------------------------------------------------ #
36
+ # Required operations #
37
+ # ------------------------------------------------------------------ #
38
+
39
+ @abstractmethod
40
+ def append(self, value: T, side: _Side = "right") -> None:
41
+ """
42
+ Add *value* to one end of the deque.
43
+
44
+ Parameters
45
+ ----------
46
+ value:
47
+ The element to add.
48
+ side:
49
+ ``"left"`` to prepend (front), ``"right"`` to append (rear).
50
+ """
51
+ ...
52
+
53
+ @abstractmethod
54
+ def pop(self, side: _Side = "right") -> T:
55
+ """
56
+ Remove and return an element from one end.
57
+
58
+ Parameters
59
+ ----------
60
+ side:
61
+ ``"left"`` to remove from the front, ``"right"`` to remove from
62
+ the rear.
63
+
64
+ Returns
65
+ -------
66
+ T
67
+
68
+ Raises
69
+ ------
70
+ EmptyStructureError
71
+ If the deque is empty.
72
+ """
73
+ ...
74
+
75
+ @abstractmethod
76
+ def peek(self, side: _Side = "left") -> T:
77
+ """
78
+ Return an element from one end without removing it.
79
+
80
+ Parameters
81
+ ----------
82
+ side:
83
+ ``"left"`` to inspect the front, ``"right"`` to inspect the rear.
84
+
85
+ Returns
86
+ -------
87
+ T
88
+
89
+ Raises
90
+ ------
91
+ EmptyStructureError
92
+ If the deque is empty.
93
+ """
94
+ ...
95
+
96
+ # ------------------------------------------------------------------ #
97
+ # Bulk operations #
98
+ # ------------------------------------------------------------------ #
99
+
100
+ @abstractmethod
101
+ def rotate(self, steps: int = 1) -> None:
102
+ """
103
+ Rotate the deque *steps* positions to the right.
104
+
105
+ Negative *steps* rotates to the left.
106
+
107
+ Parameters
108
+ ----------
109
+ steps:
110
+ Number of positions to rotate (default 1).
111
+ """
112
+ ...
113
+
114
+ @abstractmethod
115
+ def reverse(self) -> None:
116
+ """Reverse the order of all elements in the deque."""
117
+ ...
118
+
119
+ # ------------------------------------------------------------------ #
120
+ # Query operations #
121
+ # ------------------------------------------------------------------ #
122
+
123
+ @abstractmethod
124
+ def is_empty(self) -> bool:
125
+ """
126
+ Return ``True`` if the deque contains no elements.
127
+
128
+ Returns
129
+ -------
130
+ bool
131
+ """
132
+ ...
133
+
134
+ @abstractmethod
135
+ def size(self) -> int:
136
+ """
137
+ Return the number of elements in the deque.
138
+
139
+ Returns
140
+ -------
141
+ int
142
+ """
143
+ ...
144
+
145
+ @abstractmethod
146
+ def clear(self) -> None:
147
+ """Remove all elements from the deque."""
148
+ ...
149
+
150
+ @abstractmethod
151
+ def copy(self) -> Deque[T]:
152
+ """
153
+ Return a shallow copy of this deque.
154
+
155
+ Returns
156
+ -------
157
+ Deque[T]
158
+ """
159
+ ...
160
+
161
+ @abstractmethod
162
+ def to_list(self) -> list[T]:
163
+ """
164
+ Return a list of all elements, from left to right.
165
+
166
+ Returns
167
+ -------
168
+ list[T]
169
+ """
170
+ ...
171
+
172
+ # ------------------------------------------------------------------ #
173
+ # Dunder methods #
174
+ # ------------------------------------------------------------------ #
175
+
176
+ @abstractmethod
177
+ def __iter__(self) -> Iterator[T]:
178
+ ...
179
+
180
+ @abstractmethod
181
+ def __len__(self) -> int:
182
+ ...
183
+
184
+ @abstractmethod
185
+ def __bool__(self) -> bool:
186
+ ...
187
+
188
+ @abstractmethod
189
+ def __repr__(self) -> str:
190
+ ...
191
+
192
+ @abstractmethod
193
+ def __eq__(self, other: object) -> bool:
194
+ ...
@@ -0,0 +1,198 @@
1
+ """
2
+ pkstruct.linear.deques.linked_deque
3
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4
+ A double-ended queue backed by a ``DoublyLinkedList``.
5
+
6
+ ``LinkedDeque`` composes the existing production-grade doubly-linked list,
7
+ giving O(1) append and pop at both ends without any node-management code.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ from collections.abc import Iterator
13
+ from typing import Literal, TypeVar, cast
14
+
15
+ from pkstruct.linear.deques.deque import Deque
16
+ from pkstruct.linear.exceptions import EmptyStructureError
17
+ from pkstruct.linear.linked_lists.doubly_linked_list import DoublyLinkedList
18
+ from pkstruct.shared.threading import StructureLock
19
+
20
+ T = TypeVar("T")
21
+
22
+ _Side = Literal["left", "right"]
23
+
24
+
25
+ class LinkedDeque(Deque[T]):
26
+ """
27
+ A thread-safe double-ended queue implemented on top of ``DoublyLinkedList``.
28
+
29
+ The internal list stores elements from left to right. ``append(side="left")``
30
+ inserts at the head, ``append(side="right")`` appends at the tail — both O(1).
31
+
32
+ Parameters
33
+ ----------
34
+ items:
35
+ Optional iterable of initial values (left-to-right order).
36
+ If omitted the deque starts empty.
37
+
38
+ Examples
39
+ --------
40
+ >>> d = LinkedDeque([1, 2, 3])
41
+ >>> d.append(0, side="left")
42
+ >>> d.append(4, side="right")
43
+ >>> d.pop(side="left")
44
+ 0
45
+ >>> d.pop(side="right")
46
+ 4
47
+ >>> list(d)
48
+ [1, 2, 3]
49
+ """
50
+
51
+ __slots__ = ("_list", "_lock")
52
+
53
+ def __init__(self, items: list[T] | None = None) -> None:
54
+ self._list: DoublyLinkedList[T] = DoublyLinkedList()
55
+ self._lock: StructureLock = StructureLock()
56
+ if items is not None:
57
+ for item in items:
58
+ self._list.insert(item)
59
+
60
+ # ------------------------------------------------------------------ #
61
+ # Core operations #
62
+ # ------------------------------------------------------------------ #
63
+
64
+ def append(self, value: T, side: _Side = "right") -> None:
65
+ """
66
+ Add *value* to one end of the deque.
67
+
68
+ Parameters
69
+ ----------
70
+ value:
71
+ The element to add.
72
+ side:
73
+ ``"left"`` to prepend, ``"right"`` to append (default).
74
+ """
75
+ with self._lock:
76
+ if side == "left":
77
+ self._list.insert(value, position=0)
78
+ else:
79
+ self._list.insert(value)
80
+
81
+ def pop(self, side: _Side = "right") -> T:
82
+ """
83
+ Remove and return an element from one end.
84
+
85
+ Parameters
86
+ ----------
87
+ side:
88
+ ``"left"`` to remove from the front, ``"right"`` to remove from
89
+ the rear (default).
90
+
91
+ Returns
92
+ -------
93
+ T
94
+
95
+ Raises
96
+ ------
97
+ EmptyStructureError
98
+ If the deque is empty.
99
+ """
100
+ with self._lock:
101
+ if self._list.is_empty():
102
+ raise EmptyStructureError("pop from an empty deque")
103
+ if side == "left":
104
+ return cast(T, self._list.delete(position=0))
105
+ sz = self._list.size()
106
+ return cast(T, self._list.delete(position=sz - 1))
107
+
108
+ def peek(self, side: _Side = "left") -> T:
109
+ """
110
+ Return an element from one end without removing it.
111
+
112
+ Parameters
113
+ ----------
114
+ side:
115
+ ``"left"`` to inspect the front (default), ``"right"`` to inspect
116
+ the rear.
117
+
118
+ Returns
119
+ -------
120
+ T
121
+
122
+ Raises
123
+ ------
124
+ EmptyStructureError
125
+ If the deque is empty.
126
+ """
127
+ with self._lock:
128
+ if self._list.is_empty():
129
+ raise EmptyStructureError("peek at an empty deque")
130
+ if side == "left":
131
+ return self._list.get(0)
132
+ sz = self._list.size()
133
+ return self._list.get(sz - 1)
134
+
135
+ # ------------------------------------------------------------------ #
136
+ # Bulk operations #
137
+ # ------------------------------------------------------------------ #
138
+
139
+ def rotate(self, steps: int = 1) -> None:
140
+ with self._lock:
141
+ sz = self._list.size()
142
+ if sz <= 1:
143
+ return
144
+ steps = steps % sz
145
+ if steps == 0:
146
+ return
147
+ for _ in range(steps):
148
+ val: T = cast(T, self._list.delete(position=sz - 1))
149
+ self._list.insert(val, position=0)
150
+
151
+ def reverse(self) -> None:
152
+ with self._lock:
153
+ self._list.reverse()
154
+
155
+ # ------------------------------------------------------------------ #
156
+ # Query operations #
157
+ # ------------------------------------------------------------------ #
158
+
159
+ def is_empty(self) -> bool:
160
+ return self._list.is_empty()
161
+
162
+ def size(self) -> int:
163
+ return self._list.size()
164
+
165
+ def clear(self) -> None:
166
+ self._list.clear()
167
+
168
+ def copy(self) -> LinkedDeque[T]:
169
+ with self._lock:
170
+ new = LinkedDeque[T]()
171
+ new._list = cast(DoublyLinkedList[T], self._list.copy())
172
+ return new
173
+
174
+ def to_list(self) -> list[T]:
175
+ return self._list.to_list()
176
+
177
+ # ------------------------------------------------------------------ #
178
+ # Dunder methods #
179
+ # ------------------------------------------------------------------ #
180
+
181
+ def __iter__(self) -> Iterator[T]:
182
+ with self._lock:
183
+ snapshot = self.to_list()
184
+ return iter(snapshot)
185
+
186
+ def __len__(self) -> int:
187
+ return self.size()
188
+
189
+ def __bool__(self) -> bool:
190
+ return not self.is_empty()
191
+
192
+ def __repr__(self) -> str:
193
+ return f"LinkedDeque({self.to_list()!r})"
194
+
195
+ def __eq__(self, other: object) -> bool:
196
+ if not isinstance(other, LinkedDeque):
197
+ return NotImplemented
198
+ return self.to_list() == other.to_list()
@@ -0,0 +1,26 @@
1
+ """
2
+ pkstruct.linear.exceptions
3
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
4
+ Re-exports the shared exception hierarchy with linear-specific aliases.
5
+ """
6
+ from pkstruct.shared.exceptions import (
7
+ ConcurrencyError,
8
+ EmptyStructureError,
9
+ IndexOutOfRangeError,
10
+ InvalidRangeError,
11
+ PkstructError,
12
+ SerializationError,
13
+ ValidationError,
14
+ ValueNotFoundError,
15
+ )
16
+
17
+ __all__ = [
18
+ "PkstructError",
19
+ "ValidationError",
20
+ "IndexOutOfRangeError",
21
+ "ValueNotFoundError",
22
+ "EmptyStructureError",
23
+ "SerializationError",
24
+ "ConcurrencyError",
25
+ "InvalidRangeError",
26
+ ]
@@ -0,0 +1,5 @@
1
+ from pkstruct.linear.linked_lists.circular_linked_list import CircularLinkedList
2
+ from pkstruct.linear.linked_lists.doubly_linked_list import DoublyLinkedList
3
+ from pkstruct.linear.linked_lists.singly_linked_list import SinglyLinkedList
4
+
5
+ __all__ = ["SinglyLinkedList", "DoublyLinkedList", "CircularLinkedList"]