core-data-structures 1.3.0__tar.gz → 1.4.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.
Files changed (26) hide show
  1. {core_data_structures-1.3.0 → core_data_structures-1.4.0}/PKG-INFO +1 -1
  2. {core_data_structures-1.3.0 → core_data_structures-1.4.0}/core_data_structures.egg-info/PKG-INFO +1 -1
  3. {core_data_structures-1.3.0 → core_data_structures-1.4.0}/core_data_structures.egg-info/SOURCES.txt +1 -0
  4. core_data_structures-1.4.0/data_structures/trees/base.py +46 -0
  5. core_data_structures-1.4.0/data_structures/trees/binary_tree.py +246 -0
  6. {core_data_structures-1.3.0 → core_data_structures-1.4.0}/pyproject.toml +1 -1
  7. core_data_structures-1.3.0/data_structures/trees/binary_tree.py +0 -230
  8. {core_data_structures-1.3.0 → core_data_structures-1.4.0}/LICENSE +0 -0
  9. {core_data_structures-1.3.0 → core_data_structures-1.4.0}/README.rst +0 -0
  10. {core_data_structures-1.3.0 → core_data_structures-1.4.0}/core_data_structures.egg-info/dependency_links.txt +0 -0
  11. {core_data_structures-1.3.0 → core_data_structures-1.4.0}/core_data_structures.egg-info/requires.txt +0 -0
  12. {core_data_structures-1.3.0 → core_data_structures-1.4.0}/core_data_structures.egg-info/top_level.txt +0 -0
  13. {core_data_structures-1.3.0 → core_data_structures-1.4.0}/data_structures/__init__.py +0 -0
  14. {core_data_structures-1.3.0 → core_data_structures-1.4.0}/data_structures/base.py +0 -0
  15. {core_data_structures-1.3.0 → core_data_structures-1.4.0}/data_structures/graphs/__init__.py +0 -0
  16. {core_data_structures-1.3.0 → core_data_structures-1.4.0}/data_structures/graphs/graphs.py +0 -0
  17. {core_data_structures-1.3.0 → core_data_structures-1.4.0}/data_structures/graphs/vertex.py +0 -0
  18. {core_data_structures-1.3.0 → core_data_structures-1.4.0}/data_structures/lists/__init__.py +0 -0
  19. {core_data_structures-1.3.0 → core_data_structures-1.4.0}/data_structures/lists/base.py +0 -0
  20. {core_data_structures-1.3.0 → core_data_structures-1.4.0}/data_structures/lists/double_linked_list.py +0 -0
  21. {core_data_structures-1.3.0 → core_data_structures-1.4.0}/data_structures/lists/singly_linked_list.py +0 -0
  22. {core_data_structures-1.3.0 → core_data_structures-1.4.0}/data_structures/py.typed +0 -0
  23. {core_data_structures-1.3.0 → core_data_structures-1.4.0}/data_structures/trees/__init__.py +0 -0
  24. {core_data_structures-1.3.0 → core_data_structures-1.4.0}/data_structures/trees/simple_tree.py +0 -0
  25. {core_data_structures-1.3.0 → core_data_structures-1.4.0}/setup.cfg +0 -0
  26. {core_data_structures-1.3.0 → core_data_structures-1.4.0}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: core-data-structures
3
- Version: 1.3.0
3
+ Version: 1.4.0
4
4
  Summary: This project/library contains commons data structures...
5
5
  Author-email: Alejandro Cora González <alek.cora.glez@gmail.com>
6
6
  Maintainer: Alejandro Cora González
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: core-data-structures
3
- Version: 1.3.0
3
+ Version: 1.4.0
4
4
  Summary: This project/library contains commons data structures...
5
5
  Author-email: Alejandro Cora González <alek.cora.glez@gmail.com>
6
6
  Maintainer: Alejandro Cora González
@@ -18,5 +18,6 @@ data_structures/lists/base.py
18
18
  data_structures/lists/double_linked_list.py
19
19
  data_structures/lists/singly_linked_list.py
20
20
  data_structures/trees/__init__.py
21
+ data_structures/trees/base.py
21
22
  data_structures/trees/binary_tree.py
22
23
  data_structures/trees/simple_tree.py
@@ -0,0 +1,46 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ """Node with left/right child references, shared by every binary tree."""
4
+
5
+ from typing import Optional
6
+
7
+ from core_mixins.compatibility import Self
8
+
9
+ from data_structures.base import Node as BaseNode
10
+ from data_structures.base import T
11
+
12
+ __all__ = [
13
+ "Node",
14
+ ]
15
+
16
+
17
+ class Node(BaseNode[T]):
18
+ """Node with references to its left and right children."""
19
+
20
+ def __init__(
21
+ self,
22
+ value: Optional[T] = None,
23
+ left: Optional[Self] = None,
24
+ right: Optional[Self] = None,
25
+ ) -> None:
26
+ super().__init__(value=value)
27
+ self._left = left
28
+ self._right = right
29
+
30
+ @property
31
+ def left(self) -> Optional[Self]:
32
+ """The left child of the node, if any."""
33
+ return self._left
34
+
35
+ @left.setter
36
+ def left(self, node: Optional[Self]) -> None:
37
+ self._left = node
38
+
39
+ @property
40
+ def right(self) -> Optional[Self]:
41
+ """The right child of the node, if any."""
42
+ return self._right
43
+
44
+ @right.setter
45
+ def right(self, node: Optional[Self]) -> None:
46
+ self._right = node
@@ -0,0 +1,246 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ """Binary tree data structure with recursive and iterative traversal algorithms."""
4
+
5
+ from queue import Queue
6
+ from typing import Generic, Iterator, List, Optional, cast
7
+
8
+ from data_structures.base import T
9
+ from data_structures.trees.base import Node
10
+
11
+
12
+ class BinaryTree(Generic[T]):
13
+ """
14
+ In computer science, a binary tree is a tree data structure in which
15
+ each node has at most two children, referred to as the left child
16
+ and the right child.
17
+ """
18
+
19
+ def __init__(self, value: Optional[T] = None) -> None:
20
+ self._root: Optional[Node[T]] = None if value is None else Node(value)
21
+
22
+ def __iter__(self) -> Iterator[T]:
23
+ yield from self._iter(self._root)
24
+
25
+ @classmethod
26
+ def _iter(cls, node: Optional[Node[T]]) -> Iterator[T]:
27
+ if node is None:
28
+ return
29
+
30
+ yield from cls._iter(node.left)
31
+ yield cast(T, node.value)
32
+ yield from cls._iter(node.right)
33
+
34
+ def __len__(self) -> int:
35
+ return self._count(self._root)
36
+
37
+ @classmethod
38
+ def _count(cls, node: Optional[Node[T]]) -> int:
39
+ if node is None:
40
+ return 0
41
+
42
+ return 1 + cls._count(node.left) + cls._count(node.right)
43
+
44
+ def __contains__(self, value: T) -> bool:
45
+ return any(node_value == value for node_value in self)
46
+
47
+ def __repr__(self) -> str:
48
+ return f"{type(self).__name__}({self.level_order()!r})"
49
+
50
+ @property
51
+ def root(self) -> Optional[Node[T]]:
52
+ """The root node of the tree."""
53
+ return self._root
54
+
55
+ def pre_order(self) -> List[T]:
56
+ """
57
+ >>> tree = create_example_tree()
58
+ >>> tree.pre_order()
59
+ [1, 2, 4, 8, 9, 5, 10, 11, 3, 6, 12, 13, 7, 14, 15]
60
+ """
61
+
62
+ return self._pre_order(self._root)
63
+
64
+ @classmethod
65
+ def _pre_order(cls, node: Optional[Node[T]]) -> List[T]:
66
+ if node is None:
67
+ return []
68
+
69
+ res = [cast(T, node.value)]
70
+ res.extend(cls._pre_order(node.left))
71
+ res.extend(cls._pre_order(node.right))
72
+ return res
73
+
74
+ def pre_order_iterative(self) -> List[T]:
75
+ """
76
+ >>> tree = create_example_tree()
77
+ >>> tree.pre_order_iterative()
78
+ [1, 2, 4, 8, 9, 5, 10, 11, 3, 6, 12, 13, 7, 14, 15]
79
+ """
80
+
81
+ stack: List[Node[T]] = []
82
+ node: Optional[Node[T]] = self._root
83
+ res: List[T] = []
84
+
85
+ while stack or node:
86
+ while node:
87
+ res.append(cast(T, node.value))
88
+ stack.append(node)
89
+ node = node.left
90
+
91
+ node = stack.pop()
92
+ node = node.right
93
+
94
+ return res
95
+
96
+ def in_order(self) -> List[T]:
97
+ """
98
+ >>> tree = create_example_tree()
99
+ >>> tree.in_order()
100
+ [8, 4, 9, 2, 10, 5, 11, 1, 12, 6, 13, 3, 14, 7, 15]
101
+ """
102
+
103
+ return self._in_order(self._root)
104
+
105
+ @classmethod
106
+ def _in_order(cls, node: Optional[Node[T]]) -> List[T]:
107
+ if node is None:
108
+ return []
109
+
110
+ res = cls._in_order(node.left)
111
+ res.append(cast(T, node.value))
112
+ res.extend(cls._in_order(node.right))
113
+ return res
114
+
115
+ def in_order_iterative(self) -> List[T]:
116
+ """
117
+ >>> tree = create_example_tree()
118
+ >>> tree.in_order_iterative()
119
+ [8, 4, 9, 2, 10, 5, 11, 1, 12, 6, 13, 3, 14, 7, 15]
120
+ """
121
+
122
+ res: List[T] = []
123
+ stack: List[Node[T]] = []
124
+ node: Optional[Node[T]] = self._root
125
+
126
+ while stack or node:
127
+ while node:
128
+ stack.append(node)
129
+ node = node.left
130
+
131
+ node = stack.pop()
132
+ res.append(cast(T, node.value))
133
+ node = node.right
134
+
135
+ return res
136
+
137
+ def post_order(self) -> List[T]:
138
+ """
139
+ >>> tree = create_example_tree()
140
+ >>> tree.post_order()
141
+ [8, 9, 4, 10, 11, 5, 2, 12, 13, 6, 14, 15, 7, 3, 1]
142
+ """
143
+
144
+ return self._post_order(self._root)
145
+
146
+ @classmethod
147
+ def _post_order(cls, node: Optional[Node[T]]) -> List[T]:
148
+ if node is None:
149
+ return []
150
+
151
+ res = cls._post_order(node.left)
152
+ res.extend(cls._post_order(node.right))
153
+ res.append(cast(T, node.value))
154
+ return res
155
+
156
+ def post_order_iterative(self) -> List[T]:
157
+ """
158
+ >>> tree = create_example_tree()
159
+ >>> tree.post_order_iterative()
160
+ [8, 9, 4, 10, 11, 5, 2, 12, 13, 6, 14, 15, 7, 3, 1]
161
+ """
162
+
163
+ if self._root is None:
164
+ return []
165
+
166
+ stack: List[Node[T]] = [self._root]
167
+ stack_tmp: List[Node[T]] = []
168
+
169
+ while stack:
170
+ node = stack.pop()
171
+ if node.left:
172
+ stack.append(node.left)
173
+
174
+ if node.right:
175
+ stack.append(node.right)
176
+
177
+ stack_tmp.append(node)
178
+
179
+ res: List[T] = []
180
+ while stack_tmp:
181
+ res.append(cast(T, stack_tmp.pop().value))
182
+
183
+ return res
184
+
185
+ def level_order(self) -> List[T]:
186
+ """
187
+ >>> tree = create_example_tree()
188
+ >>> tree.level_order()
189
+ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
190
+ """
191
+
192
+ res: List[T] = []
193
+ if self._root is None:
194
+ return res
195
+
196
+ q: Queue[Node[T]] = Queue()
197
+ q.put(self._root)
198
+
199
+ while not q.empty():
200
+ node_dequeued = q.get()
201
+ res.append(cast(T, node_dequeued.value))
202
+
203
+ if node_dequeued.left:
204
+ q.put(node_dequeued.left)
205
+
206
+ if node_dequeued.right:
207
+ q.put(node_dequeued.right)
208
+
209
+ return res
210
+
211
+ def depth(self) -> int:
212
+ """
213
+ The maximum depth of a binary tree is the number of nodes from the
214
+ root down to the furthest leaf node. In other words, it is
215
+ the height of a binary tree.
216
+
217
+ >>> tree = create_example_tree()
218
+ >>> tree.depth()
219
+ 4
220
+ """
221
+
222
+ return self._depth(self._root)
223
+
224
+ @classmethod
225
+ def _depth(cls, node: Optional[Node[T]]) -> int:
226
+ if node is None:
227
+ return 0
228
+
229
+ return 1 + max(cls._depth(node.left), cls._depth(node.right))
230
+
231
+
232
+ def create_example_tree() -> BinaryTree[int]:
233
+ """ Build and return a complete binary tree with 15 nodes for testing. """
234
+
235
+ tree = BinaryTree(1)
236
+ root = cast(Node[int], tree.root)
237
+ nodes = [Node(value) for value in range(2, 16)]
238
+
239
+ root.left, root.right = nodes[0], nodes[1]
240
+ nodes[0].left, nodes[0].right = nodes[2], nodes[3]
241
+ nodes[1].left, nodes[1].right = nodes[4], nodes[5]
242
+ nodes[2].left, nodes[2].right = nodes[6], nodes[7]
243
+ nodes[3].left, nodes[3].right = nodes[8], nodes[9]
244
+ nodes[4].left, nodes[4].right = nodes[10], nodes[11]
245
+ nodes[5].left, nodes[5].right = nodes[12], nodes[13]
246
+ return tree
@@ -9,7 +9,7 @@ build-backend = "setuptools.build_meta"
9
9
  [project]
10
10
  name = "core-data-structures"
11
11
  description = "This project/library contains commons data structures..."
12
- version = "1.3.0"
12
+ version = "1.4.0"
13
13
 
14
14
  authors = [
15
15
  {name = "Alejandro Cora González", email = "alek.cora.glez@gmail.com"}
@@ -1,230 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
-
3
- """Binary tree data structure with recursive and iterative traversal algorithms."""
4
-
5
- from queue import Queue
6
- from typing import List, Optional
7
-
8
-
9
- class BinaryTree:
10
- """
11
- In computer science, a binary tree is a tree data structure in which
12
- each node has at most two children, which are referred to as the
13
- left child and the right child...
14
- """
15
-
16
- def __init__(self, value) -> None:
17
- self.value = value
18
- self.right: Optional[BinaryTree] = None
19
- self.left: Optional[BinaryTree] = None
20
-
21
- @staticmethod
22
- def create_example_tree():
23
- """ Build and return a complete binary tree with 15 nodes for testing. """
24
-
25
- root = BinaryTree(1)
26
- tree_node2, tree_node3 = BinaryTree(2), BinaryTree(3)
27
- tree_node4, tree_node5 = BinaryTree(4), BinaryTree(5)
28
- tree_node6, tree_node7 = BinaryTree(6), BinaryTree(7)
29
- tree_node8, tree_node9 = BinaryTree(8), BinaryTree(9)
30
- tree_node10, tree_node11 = BinaryTree(10), BinaryTree(11)
31
- tree_node12, tree_node13 = BinaryTree(12), BinaryTree(13)
32
- tree_node14, tree_node15 = BinaryTree(14), BinaryTree(15)
33
-
34
- root.left, root.right = tree_node2, tree_node3
35
- tree_node2.left, tree_node2.right = tree_node4, tree_node5
36
- tree_node3.left, tree_node3.right = tree_node6, tree_node7
37
- tree_node4.left, tree_node4.right = tree_node8, tree_node9
38
- tree_node5.left, tree_node5.right = tree_node10, tree_node11
39
- tree_node6.left, tree_node6.right = tree_node12, tree_node13
40
- tree_node7.left, tree_node7.right = tree_node14, tree_node15
41
- return root
42
-
43
- def pre_order(self) -> List:
44
- """
45
- >>> root = BinaryTree.create_example_tree()
46
- >>> root.pre_order()
47
- [1, 2, 4, 8, 9, 5, 10, 11, 3, 6, 12, 13, 7, 14, 15]
48
- """
49
-
50
- res = [self.value]
51
- if self.left:
52
- res.extend(self.left.pre_order())
53
-
54
- if self.right:
55
- res.extend(self.right.pre_order())
56
-
57
- return res
58
-
59
- def pre_order_iterative(self) -> List:
60
- """
61
- >>> root = BinaryTree.create_example_tree()
62
- >>> root.pre_order_iterative()
63
- [1, 2, 4, 8, 9, 5, 10, 11, 3, 6, 12, 13, 7, 14, 15]
64
- """
65
-
66
- stack: List[BinaryTree] = []
67
- node: Optional[BinaryTree] = self
68
- res = []
69
-
70
- while stack or node:
71
- while node:
72
- res.append(node.value)
73
- stack.append(node)
74
- node = node.left
75
-
76
- node = stack.pop()
77
- node = node.right
78
-
79
- return res
80
-
81
- def in_order(self) -> List:
82
- """
83
- >>> root = BinaryTree.create_example_tree()
84
- >>> root.in_order()
85
- [8, 4, 9, 2, 10, 5, 11, 1, 12, 6, 13, 3, 14, 7, 15]
86
- """
87
-
88
- res = []
89
- if self.left:
90
- res.extend(self.left.in_order())
91
-
92
- res.append(self.value)
93
-
94
- if self.right:
95
- res.extend(self.right.in_order())
96
-
97
- return res
98
-
99
- def in_order_iterative(self) -> List:
100
- """
101
- >>> root = BinaryTree.create_example_tree()
102
- >>> root.in_order_iterative()
103
- [8, 4, 9, 2, 10, 5, 11, 1, 12, 6, 13, 3, 14, 7, 15]
104
- """
105
-
106
- res = []
107
- stack: List[BinaryTree] = []
108
- node: Optional[BinaryTree] = self
109
-
110
- while stack or node:
111
- while node:
112
- stack.append(node)
113
- node = node.left
114
-
115
- node = stack.pop()
116
- res.append(node.value)
117
- node = node.right
118
-
119
- return res
120
-
121
- def post_order(self) -> List:
122
- """
123
- >>> root = BinaryTree.create_example_tree()
124
- >>> root.post_order()
125
- [8, 9, 4, 10, 11, 5, 2, 12, 13, 6, 14, 15, 7, 3, 1]
126
- """
127
-
128
- res = []
129
- if self.left:
130
- res.extend(self.left.post_order())
131
-
132
- if self.right:
133
- res.extend(self.right.post_order())
134
-
135
- res.append(self.value)
136
- return res
137
-
138
- def post_order_iterative(self) -> List:
139
- """
140
- >>> root = BinaryTree.create_example_tree()
141
- >>> root.post_order_iterative()
142
- [8, 9, 4, 10, 11, 5, 2, 12, 13, 6, 14, 15, 7, 3, 1]
143
- """
144
-
145
- stack: List[BinaryTree] = [self]
146
- stack_tmp: List[BinaryTree] = []
147
-
148
- while stack:
149
- node = stack.pop()
150
- if node.left:
151
- stack.append(node.left)
152
-
153
- if node.right:
154
- stack.append(node.right)
155
-
156
- stack_tmp.append(node)
157
-
158
- res = []
159
- while stack_tmp:
160
- res.append(stack_tmp.pop().value)
161
-
162
- return res
163
-
164
- def level_order(self) -> List:
165
- """
166
- >>> root = BinaryTree.create_example_tree()
167
- >>> root.level_order()
168
- [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
169
- """
170
-
171
- res = []
172
- q: Queue[BinaryTree] = Queue()
173
- q.put(self)
174
-
175
- while not q.empty():
176
- node_dequeued = q.get()
177
- res.append(node_dequeued.value)
178
-
179
- if node_dequeued.left:
180
- q.put(node_dequeued.left)
181
-
182
- if node_dequeued.right:
183
- q.put(node_dequeued.right)
184
-
185
- return res
186
-
187
- # def level_order_iterative(self) -> List:
188
- # """
189
- # >>> root = BinaryTree.create_example_tree()
190
- # >>> root.post_order_iterative()
191
- # [8, 9, 4, 10, 11, 5, 2, 12, 13, 6, 14, 15, 7, 3, 1]
192
- # """
193
- #
194
- # stack: List[BinaryTree] = []
195
- # node, res = self, []
196
- #
197
- # while stack or node:
198
- # while node.left:
199
- # stack.append(node)
200
- # node = node.left
201
- #
202
- # res.append(node.value)
203
- # node = stack.pop()
204
- # node = node.right
205
- #
206
- # return res
207
-
208
- def depth(self):
209
- """
210
- The maximum depth of a binary tree is the number of nodes from the
211
- root down to the furthest leaf node. In other words, it is
212
- the height of a binary tree.
213
-
214
- >>> root = BinaryTree.create_example_tree()
215
- >>> root.depth()
216
- 4
217
- """
218
-
219
- if not self.left and not self.right:
220
- return 1
221
-
222
- depth_left = 0
223
- if self.left:
224
- depth_left = self.left.depth()
225
-
226
- depth_right = 0
227
- if self.right:
228
- depth_right = self.right.depth()
229
-
230
- return 1 + max(depth_left, depth_right)