pkstruct 0.1.0__tar.gz
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.
- pkstruct-0.1.0/.gitignore +0 -0
- pkstruct-0.1.0/CHANGELOG.md +23 -0
- pkstruct-0.1.0/LICENSE +21 -0
- pkstruct-0.1.0/MANIFEST.in +8 -0
- pkstruct-0.1.0/PKG-INFO +482 -0
- pkstruct-0.1.0/README.md +428 -0
- pkstruct-0.1.0/SECURITY.md +20 -0
- pkstruct-0.1.0/pkstruct_test_env/Scripts/py.test.exe +0 -0
- pkstruct-0.1.0/pkstruct_test_env/Scripts/pygmentize.exe +0 -0
- pkstruct-0.1.0/pkstruct_test_env/Scripts/pytest.exe +0 -0
- pkstruct-0.1.0/pkstruct_test_env/Scripts/python.exe +0 -0
- pkstruct-0.1.0/pkstruct_test_env/Scripts/pythonw.exe +0 -0
- pkstruct-0.1.0/pkstruct_test_env/pyvenv.cfg +3 -0
- pkstruct-0.1.0/pyproject.toml +73 -0
- pkstruct-0.1.0/requirements-dev.txt +9 -0
- pkstruct-0.1.0/src/pkstruct/__init__.py +167 -0
- pkstruct-0.1.0/src/pkstruct/graphs/__init__.py +127 -0
- pkstruct-0.1.0/src/pkstruct/graphs/connectivity.py +157 -0
- pkstruct-0.1.0/src/pkstruct/graphs/directed.py +95 -0
- pkstruct-0.1.0/src/pkstruct/graphs/exceptions.py +63 -0
- pkstruct-0.1.0/src/pkstruct/graphs/graph.py +262 -0
- pkstruct-0.1.0/src/pkstruct/graphs/mst.py +118 -0
- pkstruct-0.1.0/src/pkstruct/graphs/scc.py +138 -0
- pkstruct-0.1.0/src/pkstruct/graphs/shortest_path.py +250 -0
- pkstruct-0.1.0/src/pkstruct/graphs/tests/__init__.py +2 -0
- pkstruct-0.1.0/src/pkstruct/graphs/tests/test_graph.py +626 -0
- pkstruct-0.1.0/src/pkstruct/graphs/tests/test_graph_advanced.py +1402 -0
- pkstruct-0.1.0/src/pkstruct/graphs/topo_sort.py +108 -0
- pkstruct-0.1.0/src/pkstruct/graphs/traversal.py +175 -0
- pkstruct-0.1.0/src/pkstruct/graphs/visualization.py +90 -0
- pkstruct-0.1.0/src/pkstruct/graphs/weighted.py +37 -0
- pkstruct-0.1.0/src/pkstruct/linear/__init__.py +95 -0
- pkstruct-0.1.0/src/pkstruct/linear/deques/__init__.py +33 -0
- pkstruct-0.1.0/src/pkstruct/linear/deques/deque.py +194 -0
- pkstruct-0.1.0/src/pkstruct/linear/deques/linked_deque.py +198 -0
- pkstruct-0.1.0/src/pkstruct/linear/exceptions.py +26 -0
- pkstruct-0.1.0/src/pkstruct/linear/linked_lists/__init__.py +5 -0
- pkstruct-0.1.0/src/pkstruct/linear/linked_lists/_base.py +608 -0
- pkstruct-0.1.0/src/pkstruct/linear/linked_lists/circular_linked_list.py +230 -0
- pkstruct-0.1.0/src/pkstruct/linear/linked_lists/doubly_linked_list.py +151 -0
- pkstruct-0.1.0/src/pkstruct/linear/linked_lists/nodes.py +68 -0
- pkstruct-0.1.0/src/pkstruct/linear/linked_lists/singly_linked_list.py +136 -0
- pkstruct-0.1.0/src/pkstruct/linear/queues/__init__.py +44 -0
- pkstruct-0.1.0/src/pkstruct/linear/queues/circular_queue.py +258 -0
- pkstruct-0.1.0/src/pkstruct/linear/queues/linked_queue.py +186 -0
- pkstruct-0.1.0/src/pkstruct/linear/queues/priority_queue.py +202 -0
- pkstruct-0.1.0/src/pkstruct/linear/queues/queue.py +174 -0
- pkstruct-0.1.0/src/pkstruct/linear/stacks/__init__.py +38 -0
- pkstruct-0.1.0/src/pkstruct/linear/stacks/array_stack.py +165 -0
- pkstruct-0.1.0/src/pkstruct/linear/stacks/linked_stack.py +168 -0
- pkstruct-0.1.0/src/pkstruct/linear/stacks/stack.py +158 -0
- pkstruct-0.1.0/src/pkstruct/linear/tests/__init__.py +2 -0
- pkstruct-0.1.0/src/pkstruct/linear/tests/test_edge_cases.py +195 -0
- pkstruct-0.1.0/src/pkstruct/linear/tests/test_linked_list.py +673 -0
- pkstruct-0.1.0/src/pkstruct/linear/tests/test_visualization.py +92 -0
- pkstruct-0.1.0/src/pkstruct/linear/utils/__init__.py +18 -0
- pkstruct-0.1.0/src/pkstruct/linear/utils/benchmark.py +255 -0
- pkstruct-0.1.0/src/pkstruct/linear/utils/debug_tools.py +239 -0
- pkstruct-0.1.0/src/pkstruct/linear/utils/helpers.py +143 -0
- pkstruct-0.1.0/src/pkstruct/linear/utils/iterators.py +148 -0
- pkstruct-0.1.0/src/pkstruct/linear/visualization/__init__.py +0 -0
- pkstruct-0.1.0/src/pkstruct/linear/visualization/ascii_visualizer.py +114 -0
- pkstruct-0.1.0/src/pkstruct/linear/visualization/linked_list_visualizer.py +126 -0
- pkstruct-0.1.0/src/pkstruct/shared/__init__.py +67 -0
- pkstruct-0.1.0/src/pkstruct/shared/benchmarking/__init__.py +78 -0
- pkstruct-0.1.0/src/pkstruct/shared/debugging/__init__.py +69 -0
- pkstruct-0.1.0/src/pkstruct/shared/exceptions/__init__.py +59 -0
- pkstruct-0.1.0/src/pkstruct/shared/serializers/__init__.py +65 -0
- pkstruct-0.1.0/src/pkstruct/shared/threading/__init__.py +43 -0
- pkstruct-0.1.0/src/pkstruct/shared/validators/__init__.py +98 -0
- pkstruct-0.1.0/src/pkstruct/shared/visualization/__init__.py +21 -0
- pkstruct-0.1.0/src/pkstruct/trees/__init__.py +92 -0
- pkstruct-0.1.0/src/pkstruct/trees/avl.py +321 -0
- pkstruct-0.1.0/src/pkstruct/trees/balancing.py +253 -0
- pkstruct-0.1.0/src/pkstruct/trees/bplus.py +425 -0
- pkstruct-0.1.0/src/pkstruct/trees/bst.py +948 -0
- pkstruct-0.1.0/src/pkstruct/trees/btree.py +504 -0
- pkstruct-0.1.0/src/pkstruct/trees/exceptions.py +96 -0
- pkstruct-0.1.0/src/pkstruct/trees/fenwick_tree.py +312 -0
- pkstruct-0.1.0/src/pkstruct/trees/interval_tree.py +541 -0
- pkstruct-0.1.0/src/pkstruct/trees/node.py +356 -0
- pkstruct-0.1.0/src/pkstruct/trees/red_black.py +710 -0
- pkstruct-0.1.0/src/pkstruct/trees/segment_tree.py +398 -0
- pkstruct-0.1.0/src/pkstruct/trees/tests/__init__.py +2 -0
- pkstruct-0.1.0/src/pkstruct/trees/tests/test_avl.py +414 -0
- pkstruct-0.1.0/src/pkstruct/trees/tests/test_bplus.py +311 -0
- pkstruct-0.1.0/src/pkstruct/trees/tests/test_bst.py +553 -0
- pkstruct-0.1.0/src/pkstruct/trees/tests/test_btree.py +302 -0
- pkstruct-0.1.0/src/pkstruct/trees/tests/test_fenwick_tree.py +232 -0
- pkstruct-0.1.0/src/pkstruct/trees/tests/test_interval_tree.py +336 -0
- pkstruct-0.1.0/src/pkstruct/trees/tests/test_red_black.py +369 -0
- pkstruct-0.1.0/src/pkstruct/trees/tests/test_segment_tree.py +242 -0
- pkstruct-0.1.0/src/pkstruct/trees/traversal.py +456 -0
- pkstruct-0.1.0/src/pkstruct/trees/tree_helpers.py +366 -0
- pkstruct-0.1.0/src/pkstruct/trees/utils/__init__.py +15 -0
- pkstruct-0.1.0/src/pkstruct/trees/utils/complexity_helpers.py +231 -0
- pkstruct-0.1.0/src/pkstruct/trees/visualization/__init__.py +0 -0
- pkstruct-0.1.0/src/pkstruct/trees/visualization/ascii_renderer.py +220 -0
- pkstruct-0.1.0/src/pkstruct/trees/visualization/tree_printer.py +129 -0
- pkstruct-0.1.0/testing_final.py +1148 -0
|
Binary file
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to pkstruct will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.1.0] - 2026-06-01
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- `pkstruct.linear` module with `SinglyLinkedList`, `DoublyLinkedList`, `CircularLinkedList`
|
|
12
|
+
- Full CRUD operations: `insert`, `delete`, `get`, `replace`, `extend`, `clear`
|
|
13
|
+
- Algorithmic operations: `sort`, `merge`, `partition`, `reverse`, `rotate`, `swap`
|
|
14
|
+
- Interview problems: `detect_cycle`, `intersection_node`, `palindrome`, `reorder`, `segregate_even_odd`
|
|
15
|
+
- Serialization: `from_list`, `from_json`, `to_list`, `copy`
|
|
16
|
+
- ASCII visualization with `visualize()` and `debug()` introspection
|
|
17
|
+
- Thread-safe operations via `RLock`
|
|
18
|
+
- Custom exception hierarchy via `pkstruct.linear.exceptions`
|
|
19
|
+
- Shared subsystem (`pkstruct.shared`) for validators, serializers, threading, benchmarking
|
|
20
|
+
- Full pytest suite with edge cases, randomization, and threading tests
|
|
21
|
+
- Benchmark suite comparing against `list` and `collections.deque`
|
|
22
|
+
- Type annotations, mypy strict compliance
|
|
23
|
+
- PyPI-ready packaging with `hatchling`
|
pkstruct-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Prannavakhanth
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
pkstruct-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,482 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pkstruct
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Industrial-grade data structures and algorithms toolkit for Python
|
|
5
|
+
Project-URL: Homepage, https://github.com/pkstruct/pkstruct
|
|
6
|
+
Project-URL: Repository, https://github.com/pkstruct/pkstruct
|
|
7
|
+
Project-URL: Documentation, https://pkstruct.readthedocs.io
|
|
8
|
+
Project-URL: Bug Tracker, https://github.com/pkstruct/pkstruct/issues
|
|
9
|
+
Author: pkstruct Contributors
|
|
10
|
+
License: MIT License
|
|
11
|
+
|
|
12
|
+
Copyright (c) 2026 Prannavakhanth
|
|
13
|
+
|
|
14
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
15
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
16
|
+
in the Software without restriction, including without limitation the rights
|
|
17
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
18
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
19
|
+
furnished to do so, subject to the following conditions:
|
|
20
|
+
|
|
21
|
+
The above copyright notice and this permission notice shall be included in all
|
|
22
|
+
copies or substantial portions of the Software.
|
|
23
|
+
|
|
24
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
25
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
26
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
27
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
28
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
29
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
30
|
+
SOFTWARE.
|
|
31
|
+
License-File: LICENSE
|
|
32
|
+
Keywords: algorithms,collections,data-structures,dsa,linked-list
|
|
33
|
+
Classifier: Development Status :: 4 - Beta
|
|
34
|
+
Classifier: Intended Audience :: Developers
|
|
35
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
36
|
+
Classifier: Programming Language :: Python :: 3
|
|
37
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
38
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
39
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
40
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
41
|
+
Classifier: Typing :: Typed
|
|
42
|
+
Requires-Python: >=3.10
|
|
43
|
+
Provides-Extra: dev
|
|
44
|
+
Requires-Dist: black>=23.11; extra == 'dev'
|
|
45
|
+
Requires-Dist: build>=1.0; extra == 'dev'
|
|
46
|
+
Requires-Dist: mypy>=1.7; extra == 'dev'
|
|
47
|
+
Requires-Dist: pytest-benchmark>=4.0; extra == 'dev'
|
|
48
|
+
Requires-Dist: pytest-cov>=4.1; extra == 'dev'
|
|
49
|
+
Requires-Dist: pytest-xdist>=3.3; extra == 'dev'
|
|
50
|
+
Requires-Dist: pytest>=7.4; extra == 'dev'
|
|
51
|
+
Requires-Dist: ruff>=0.1.6; extra == 'dev'
|
|
52
|
+
Requires-Dist: twine>=4.0; extra == 'dev'
|
|
53
|
+
Description-Content-Type: text/markdown
|
|
54
|
+
|
|
55
|
+
# pkstruct
|
|
56
|
+
|
|
57
|
+
**Industrial-grade data structures and algorithms for Python ≥ 3.10**
|
|
58
|
+
|
|
59
|
+
[](https://pypi.org/project/pkstruct/)
|
|
60
|
+
[](https://pypi.org/project/pkstruct/)
|
|
61
|
+
[](LICENSE)
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## Installation
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
pip install pkstruct
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Quick Start
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
from pkstruct.linear import SinglyLinkedList, DoublyLinkedList, CircularLinkedList
|
|
75
|
+
|
|
76
|
+
# Singly Linked List
|
|
77
|
+
sll = SinglyLinkedList.from_list([1, 2, 3, 4, 5])
|
|
78
|
+
sll.insert(99, position=2) # [1, 2, 99, 3, 4, 5]
|
|
79
|
+
sll.sort() # [1, 2, 3, 4, 5, 99]
|
|
80
|
+
print(sll.visualize())
|
|
81
|
+
# [1] -> [2] -> [3] -> [4] -> [5] -> [99] -> NULL
|
|
82
|
+
|
|
83
|
+
# Doubly Linked List
|
|
84
|
+
dll = DoublyLinkedList.from_list([10, 20, 30])
|
|
85
|
+
dll.reverse()
|
|
86
|
+
print(dll.visualize())
|
|
87
|
+
# None <- 30 <-> 20 <-> 10 -> None
|
|
88
|
+
|
|
89
|
+
# Circular Linked List
|
|
90
|
+
cll = CircularLinkedList.from_list(["a", "b", "c"])
|
|
91
|
+
cll.rotate(shift=1)
|
|
92
|
+
print(cll.visualize())
|
|
93
|
+
# c -> a -> b -> (back to head)
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
from pkstruct.trees import BinarySearchTree, AVLTree, RedBlackTree, SegmentTree
|
|
98
|
+
|
|
99
|
+
# Binary Search Tree
|
|
100
|
+
bst = BinarySearchTree()
|
|
101
|
+
bst.insert(10)
|
|
102
|
+
bst.insert(5)
|
|
103
|
+
bst.insert(15)
|
|
104
|
+
list(bst) # [5, 10, 15]
|
|
105
|
+
10 in bst # True
|
|
106
|
+
|
|
107
|
+
# AVL Tree (self-balancing)
|
|
108
|
+
avl = AVLTree.from_list([1, 2, 3, 4, 5])
|
|
109
|
+
avl.height() # 2 (logarithmic, not linear)
|
|
110
|
+
|
|
111
|
+
# Segment Tree with lazy propagation
|
|
112
|
+
st = SegmentTree([1, 2, 3, 4, 5], func="sum")
|
|
113
|
+
st.query(1, 3) # 9 (2 + 3 + 4)
|
|
114
|
+
st.update(2, 10) # point update
|
|
115
|
+
st.range_update(1, 3, 5) # range add
|
|
116
|
+
st.query(1, 3) # 24
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
```python
|
|
120
|
+
from pkstruct.graphs import Graph, DirectedGraph, bfs, dfs, dijkstra, kruskal
|
|
121
|
+
|
|
122
|
+
# Create a weighted graph
|
|
123
|
+
g = Graph()
|
|
124
|
+
g.add_edge("A", "B", weight=4.0)
|
|
125
|
+
g.add_edge("B", "C", weight=2.0)
|
|
126
|
+
g.add_edge("A", "C", weight=1.0)
|
|
127
|
+
|
|
128
|
+
# Traversal
|
|
129
|
+
bfs(g, "A") # ['A', 'B', 'C']
|
|
130
|
+
|
|
131
|
+
# Shortest paths
|
|
132
|
+
dist, _ = dijkstra(g, "A")
|
|
133
|
+
dist["C"] # 1.0
|
|
134
|
+
|
|
135
|
+
# Minimum spanning tree
|
|
136
|
+
kruskal(g) # [('A', 'C', 1.0), ('B', 'C', 2.0)]
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Modules
|
|
140
|
+
|
|
141
|
+
### `pkstruct.linear`
|
|
142
|
+
|
|
143
|
+
| Data Structure | Description |
|
|
144
|
+
|---|---|
|
|
145
|
+
| `SinglyLinkedList` | Forward-only linked list with merge sort, cycle detection, palindrome check |
|
|
146
|
+
| `DoublyLinkedList` | Bidirectional linked list with backward traversal |
|
|
147
|
+
| `CircularLinkedList` | Circular linked list maintaining circular invariant |
|
|
148
|
+
| `ArrayStack` | LIFO stack backed by a dynamic array |
|
|
149
|
+
| `LinkedStack` | LIFO stack backed by `SinglyLinkedList` |
|
|
150
|
+
| `LinkedQueue` | FIFO queue backed by `SinglyLinkedList` |
|
|
151
|
+
| `CircularQueue` | Fixed-capacity FIFO queue backed by a ring buffer |
|
|
152
|
+
| `PriorityQueue` | Min-heap priority queue |
|
|
153
|
+
| `LinkedDeque` | Double-ended queue backed by `DoublyLinkedList` |
|
|
154
|
+
|
|
155
|
+
### `pkstruct.trees`
|
|
156
|
+
|
|
157
|
+
| Data Structure | Description |
|
|
158
|
+
|---|---|
|
|
159
|
+
| `BinarySearchTree` | Unbalanced BST with full interview-utility API |
|
|
160
|
+
| `AVLTree` | Self-balancing AVL tree (extends BST) |
|
|
161
|
+
| `RedBlackTree` | Self-balancing red-black tree |
|
|
162
|
+
| `BTree` | Balanced multi-way search tree |
|
|
163
|
+
| `BPlusTree` | B+ Tree with leaf-linked chain for efficient range queries |
|
|
164
|
+
| `SegmentTree` | Segment tree with lazy propagation (sum/min/max/gcd/xor) |
|
|
165
|
+
| `FenwickTree` | Binary indexed tree for prefix-sum operations |
|
|
166
|
+
| `IntervalTree` | Augmented interval tree for overlap queries |
|
|
167
|
+
|
|
168
|
+
### `pkstruct.graphs`
|
|
169
|
+
|
|
170
|
+
| Class / Function | Description |
|
|
171
|
+
|---|---|
|
|
172
|
+
| `Graph` | Adjacency-list graph (directed/undirected, weighted) |
|
|
173
|
+
| `DirectedGraph` | Directed graph with in-degree, out-degree, reverse |
|
|
174
|
+
| `WeightedGraph` | Convenience class for weighted undirected graphs |
|
|
175
|
+
| `bfs` / `dfs` | Breadth-first and depth-first search |
|
|
176
|
+
| `bfs_paths` / `dfs_paths` | Find all paths between two vertices |
|
|
177
|
+
| `dijkstra` | Shortest paths (non-negative weights) |
|
|
178
|
+
| `bellman_ford` | Shortest paths (negative weights allowed) |
|
|
179
|
+
| `floyd_warshall` | All-pairs shortest paths |
|
|
180
|
+
| `reconstruct_path` | Path reconstruction from Dijkstra / Bellman-Ford |
|
|
181
|
+
| `reconstruct_path_fw` | Path reconstruction from Floyd-Warshall |
|
|
182
|
+
| `kruskal` / `prim` | Minimum spanning tree |
|
|
183
|
+
| `connected_components` | Find all connected components |
|
|
184
|
+
| `is_connected` / `is_bipartite` | Connectivity checks |
|
|
185
|
+
| `has_cycle` / `has_cycle_directed` | Cycle detection |
|
|
186
|
+
| `topological_sort_kahn` / `topological_sort_dfs` | Topological sort |
|
|
187
|
+
| `kosaraju` / `tarjan` | Strongly connected components |
|
|
188
|
+
| `visualize` / `adjacency_matrix` | ASCII visualization |
|
|
189
|
+
|
|
190
|
+
**Exceptions:** `GraphError`, `VertexNotFoundError`, `EdgeNotFoundError`,
|
|
191
|
+
`InvalidGraphOperationError`, `NegativeCycleError`, `NoPathError`
|
|
192
|
+
|
|
193
|
+
## Features
|
|
194
|
+
|
|
195
|
+
### Linked Lists
|
|
196
|
+
|
|
197
|
+
| Feature | SLL | DLL | CLL |
|
|
198
|
+
|---|---|---|---|
|
|
199
|
+
| Insert / Delete | ✅ | ✅ | ✅ |
|
|
200
|
+
| Sort (merge sort) | ✅ | ✅ | ✅ |
|
|
201
|
+
| Reverse (partial) | ✅ | ✅ | ✅ |
|
|
202
|
+
| Rotate (sub-range) | ✅ | ✅ | ✅ |
|
|
203
|
+
| Swap elements | ✅ | ✅ | ✅ |
|
|
204
|
+
| Cycle detection | ✅ | ✅ | — |
|
|
205
|
+
| Palindrome check | ✅ | ✅ | — |
|
|
206
|
+
| Even-odd segregation | ✅ | ✅ | — |
|
|
207
|
+
| JSON serialization | ✅ | ✅ | ✅ |
|
|
208
|
+
| ASCII visualization | ✅ | ✅ | ✅ |
|
|
209
|
+
| Thread-safe (RLock) | ✅ | ✅ | ✅ |
|
|
210
|
+
| `__slots__` nodes | ✅ | ✅ | ✅ |
|
|
211
|
+
|
|
212
|
+
## API Overview
|
|
213
|
+
|
|
214
|
+
### Linear — Linked Lists
|
|
215
|
+
|
|
216
|
+
```python
|
|
217
|
+
# Construction
|
|
218
|
+
ll = SinglyLinkedList() # empty
|
|
219
|
+
ll = SinglyLinkedList.from_list([1, 2, 3])
|
|
220
|
+
ll = SinglyLinkedList.from_json('{"items": [1, 2, 3]}')
|
|
221
|
+
|
|
222
|
+
# Insertion
|
|
223
|
+
ll.insert(99) # append at tail
|
|
224
|
+
ll.insert(99, position=0) # insert at head
|
|
225
|
+
ll.insert(99, before=50) # insert before value
|
|
226
|
+
ll.insert(99, after=50) # insert after value
|
|
227
|
+
|
|
228
|
+
# Deletion
|
|
229
|
+
ll.delete(position=2) # delete by index
|
|
230
|
+
ll.delete(value=42) # delete by value (first match)
|
|
231
|
+
ll.delete(rng=(1, 3)) # delete sub-range [1..3]
|
|
232
|
+
ll.clear() # remove all
|
|
233
|
+
|
|
234
|
+
# Access
|
|
235
|
+
ll.get(0) # by index
|
|
236
|
+
ll[0] # via __getitem__
|
|
237
|
+
ll.index(42) # find first occurrence
|
|
238
|
+
ll.count(42) # count occurrences
|
|
239
|
+
|
|
240
|
+
# Mutation
|
|
241
|
+
ll[0] = 99 # via __setitem__
|
|
242
|
+
ll.swap(0, 2) # swap two positions
|
|
243
|
+
ll.reverse() # full reverse
|
|
244
|
+
ll.reverse(start=1, end=3) # sub-range reverse
|
|
245
|
+
ll.rotate(shift=2) # rotate whole list right
|
|
246
|
+
ll.rotate(shift=2, start=1, end=4) # rotate sub-range
|
|
247
|
+
ll.sort() # ascending
|
|
248
|
+
ll.sort(reverse=True) # descending
|
|
249
|
+
ll.merge(other_list) # merge in-place
|
|
250
|
+
|
|
251
|
+
# Interview helpers
|
|
252
|
+
ll.palindrome() # palindrome check
|
|
253
|
+
ll.detect_cycle() # Floyd's algorithm
|
|
254
|
+
ll.segregate_even_odd() # reorder
|
|
255
|
+
ll.partition(5) # pivot partition
|
|
256
|
+
|
|
257
|
+
# Serialization
|
|
258
|
+
json_str = ll.to_json()
|
|
259
|
+
ll = SinglyLinkedList.from_json(json_str)
|
|
260
|
+
|
|
261
|
+
# Visualization
|
|
262
|
+
print(ll.visualize()) # ASCII art
|
|
263
|
+
info = ll.debug() # diagnostic dict
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
### Linear — Stacks, Queues, Deques
|
|
267
|
+
|
|
268
|
+
```python
|
|
269
|
+
from pkstruct.linear import ArrayStack, LinkedStack, LinkedQueue, CircularQueue, PriorityQueue, LinkedDeque
|
|
270
|
+
|
|
271
|
+
# Stack
|
|
272
|
+
s = LinkedStack([1, 2, 3])
|
|
273
|
+
s.push(4)
|
|
274
|
+
s.pop() # 4
|
|
275
|
+
s.peek() # 3
|
|
276
|
+
len(s) # 3
|
|
277
|
+
|
|
278
|
+
# Queue
|
|
279
|
+
q = LinkedQueue([1, 2, 3])
|
|
280
|
+
q.enqueue(4)
|
|
281
|
+
q.dequeue() # 1
|
|
282
|
+
q.peek() # 2
|
|
283
|
+
|
|
284
|
+
# Circular Queue (fixed capacity)
|
|
285
|
+
cq = CircularQueue(capacity=3)
|
|
286
|
+
cq.enqueue(1)
|
|
287
|
+
cq.enqueue(2)
|
|
288
|
+
cq.enqueue(3)
|
|
289
|
+
cq.is_full() # True
|
|
290
|
+
cq.dequeue() # 1
|
|
291
|
+
|
|
292
|
+
# Priority Queue (min-heap)
|
|
293
|
+
pq = PriorityQueue()
|
|
294
|
+
pq.push("task1", priority=3)
|
|
295
|
+
pq.push("task2", priority=1)
|
|
296
|
+
pq.pop() # "task2"
|
|
297
|
+
|
|
298
|
+
# Deque
|
|
299
|
+
d = LinkedDeque([1, 2, 3])
|
|
300
|
+
d.append(4)
|
|
301
|
+
d.appendleft(0)
|
|
302
|
+
d.pop() # 4
|
|
303
|
+
d.popleft() # 0
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
### Trees
|
|
307
|
+
|
|
308
|
+
```python
|
|
309
|
+
# Binary Search Tree
|
|
310
|
+
bst = BinarySearchTree()
|
|
311
|
+
bst.insert(10, value="ten")
|
|
312
|
+
bst.insert(5, value="five")
|
|
313
|
+
bst[5] # "five"
|
|
314
|
+
bst.search(10) # ("ten", Node)
|
|
315
|
+
bst.delete(5)
|
|
316
|
+
len(bst) # 1
|
|
317
|
+
|
|
318
|
+
# Traversals
|
|
319
|
+
list(bst.inorder()) # [5, 10, 15]
|
|
320
|
+
list(bst.preorder()) # [10, 5, 15]
|
|
321
|
+
list(bst.postorder()) # [5, 15, 10]
|
|
322
|
+
list(bst.level_order()) # [10, 5, 15]
|
|
323
|
+
list(bst.zigzag()) # [10, 15, 5]
|
|
324
|
+
|
|
325
|
+
# Utilities
|
|
326
|
+
bst.find_lca(5, 15) # 10 (lowest common ancestor)
|
|
327
|
+
bst.kth_smallest(1) # 5
|
|
328
|
+
bst.kth_largest(1) # 15
|
|
329
|
+
bst.range_query(5, 15) # [5, 10, 15]
|
|
330
|
+
bst.path_sum(20) # True
|
|
331
|
+
bst.root_to_leaf_paths() # [[10, 5], [10, 15]]
|
|
332
|
+
bst.diameter() # 2
|
|
333
|
+
bst.is_balanced() # True
|
|
334
|
+
bst.invert()
|
|
335
|
+
|
|
336
|
+
# AVL Tree (self-balancing)
|
|
337
|
+
avl = AVLTree()
|
|
338
|
+
avl.insert(3)
|
|
339
|
+
avl.insert(2)
|
|
340
|
+
avl.insert(1) # triggers LL rotation
|
|
341
|
+
avl.is_avl_valid() # True
|
|
342
|
+
avl.height() # 1
|
|
343
|
+
|
|
344
|
+
# Red-Black Tree
|
|
345
|
+
rbt = RedBlackTree()
|
|
346
|
+
rbt.insert(10)
|
|
347
|
+
rbt.insert(20)
|
|
348
|
+
rbt.insert(30) # triggers recoloring / rotation
|
|
349
|
+
rbt.validate() # checks red-black invariants
|
|
350
|
+
|
|
351
|
+
# B-Tree & B+ Tree
|
|
352
|
+
bt = BTree(order=4)
|
|
353
|
+
bt.insert(10)
|
|
354
|
+
bt.insert(20)
|
|
355
|
+
bt.insert(5)
|
|
356
|
+
bt.search(10) # True
|
|
357
|
+
|
|
358
|
+
bpt = BPlusTree(order=4)
|
|
359
|
+
bpt.insert(10)
|
|
360
|
+
bpt.insert(20)
|
|
361
|
+
bpt.range_query(5, 15) # efficient via leaf chain
|
|
362
|
+
|
|
363
|
+
# Segment Tree
|
|
364
|
+
st = SegmentTree([1, 2, 3, 4, 5], func="sum")
|
|
365
|
+
st.query(0, 2) # 6
|
|
366
|
+
st.range_update(0, 2, 3) # range add
|
|
367
|
+
st.query(0, 2) # 15
|
|
368
|
+
st.rebuild([5, 6, 7, 8])
|
|
369
|
+
|
|
370
|
+
# Fenwick Tree
|
|
371
|
+
ft = FenwickTree(5)
|
|
372
|
+
ft.add(1, 10)
|
|
373
|
+
ft.add(2, 20)
|
|
374
|
+
ft.prefix_sum(2) # 30
|
|
375
|
+
ft.range_sum(1, 2) # 30
|
|
376
|
+
|
|
377
|
+
# Interval Tree
|
|
378
|
+
it = IntervalTree()
|
|
379
|
+
it.insert(5, 10, "A")
|
|
380
|
+
it.insert(15, 20, "B")
|
|
381
|
+
it.overlap(8, 12) # [(5, 10, "A")]
|
|
382
|
+
it.overlap_all(8, 12) # all overlapping intervals
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
### Graphs
|
|
386
|
+
|
|
387
|
+
```python
|
|
388
|
+
from pkstruct.graphs import Graph, DirectedGraph, WeightedGraph
|
|
389
|
+
from pkstruct.graphs import bfs, dfs, dijkstra, bellman_ford, floyd_warshall
|
|
390
|
+
from pkstruct.graphs import reconstruct_path, kruskal, kosaraju
|
|
391
|
+
|
|
392
|
+
# Create a graph
|
|
393
|
+
g = Graph()
|
|
394
|
+
g.add_edge("A", "B", weight=4.0)
|
|
395
|
+
g.add_edge("B", "C", weight=2.0)
|
|
396
|
+
g.add_edge("A", "C", weight=1.0)
|
|
397
|
+
|
|
398
|
+
# Traversal
|
|
399
|
+
bfs(g, "A") # ['A', 'B', 'C']
|
|
400
|
+
dfs(g, "A") # ['A', 'B', 'C']
|
|
401
|
+
|
|
402
|
+
# Shortest path (Dijkstra)
|
|
403
|
+
dist, pred = dijkstra(g, "A")
|
|
404
|
+
dist["C"] # 1.0
|
|
405
|
+
reconstruct_path(pred, "A", "C") # ['A', 'C']
|
|
406
|
+
|
|
407
|
+
# Minimum spanning tree
|
|
408
|
+
mst = kruskal(g) # [('A', 'C', 1.0), ('B', 'C', 2.0)]
|
|
409
|
+
|
|
410
|
+
# Bellman-Ford (supports negative weights)
|
|
411
|
+
dist, pred = bellman_ford(g, "A")
|
|
412
|
+
dist["C"] # 1.0
|
|
413
|
+
|
|
414
|
+
# All-pairs shortest paths
|
|
415
|
+
dist_all, _ = floyd_warshall(g)
|
|
416
|
+
dist_all["A"]["C"] # 1.0
|
|
417
|
+
|
|
418
|
+
# Directed graph
|
|
419
|
+
dg = DirectedGraph()
|
|
420
|
+
dg.add_edge("A", "B")
|
|
421
|
+
dg.add_edge("B", "C")
|
|
422
|
+
dg.add_edge("A", "C")
|
|
423
|
+
topological_sort_kahn(dg) # ['A', 'B', 'C']
|
|
424
|
+
|
|
425
|
+
# Strongly connected components
|
|
426
|
+
dg.add_edge("C", "A")
|
|
427
|
+
kosaraju(dg) # [['A', 'B', 'C']] (one SCC)
|
|
428
|
+
|
|
429
|
+
# Weighted graph
|
|
430
|
+
wg = WeightedGraph()
|
|
431
|
+
wg.add_edge("X", "Y", 3.5)
|
|
432
|
+
wg.add_edge("Y", "Z", 1.5)
|
|
433
|
+
wg.get_weight("X", "Y") # 3.5
|
|
434
|
+
|
|
435
|
+
# Visualization
|
|
436
|
+
from pkstruct.graphs import visualize
|
|
437
|
+
print(visualize(g))
|
|
438
|
+
# Graph (directed=False, vertices=3, edges=3)
|
|
439
|
+
# 'A' -> 'B' [4.0] <-> 'C' [1.0]
|
|
440
|
+
# 'B' -> 'A' [4.0] <-> 'C' [2.0]
|
|
441
|
+
# 'C' -> 'A' [1.0] <-> 'B' [2.0]
|
|
442
|
+
|
|
443
|
+
# Exception handling
|
|
444
|
+
from pkstruct.graphs.exceptions import VertexNotFoundError, NegativeCycleError
|
|
445
|
+
|
|
446
|
+
try:
|
|
447
|
+
g.get_weight("X", "Y")
|
|
448
|
+
except VertexNotFoundError:
|
|
449
|
+
print("Vertex does not exist")
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
## String Protocol
|
|
453
|
+
|
|
454
|
+
```python
|
|
455
|
+
sll = SinglyLinkedList.from_list([1, 2, 3])
|
|
456
|
+
list(sll) # [1, 2, 3]
|
|
457
|
+
len(sll) # 3
|
|
458
|
+
bool(sll) # True (False when empty)
|
|
459
|
+
repr(sll) # SinglyLinkedList([1, 2, 3])
|
|
460
|
+
str(sll) # SinglyLinkedList([1, 2, 3])
|
|
461
|
+
42 in sll # True / False
|
|
462
|
+
sll == other # value equality
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
## Development
|
|
466
|
+
|
|
467
|
+
```bash
|
|
468
|
+
pip install -e ".[dev]"
|
|
469
|
+
pytest src/pkstruct/linear/tests src/pkstruct/trees/tests src/pkstruct/graphs/tests -v
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
## Publishing
|
|
473
|
+
|
|
474
|
+
```bash
|
|
475
|
+
python -m build
|
|
476
|
+
twine check dist/*
|
|
477
|
+
twine upload dist/*
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
## License
|
|
481
|
+
|
|
482
|
+
MIT © pkstruct Contributors
|