|
1 | | -from pydatastructs.utils import MAryTreeNode |
| 1 | +from pydatastructs.utils import MAryTreeNode, ParentPointerTreeNode |
2 | 2 | from pydatastructs.linear_data_structures.arrays import ArrayForTrees |
3 | 3 | from pydatastructs.utils.misc_util import ( |
4 | 4 | Backend, raise_if_backend_is_not_python) |
@@ -170,3 +170,155 @@ def __str__(self): |
170 | 170 | if j is not None: |
171 | 171 | to_be_printed[i].append(j) |
172 | 172 | return str(to_be_printed) |
| 173 | + |
| 174 | +class ParentPointerTree(object): |
| 175 | + """ |
| 176 | + Implements a tree with parent pointers. |
| 177 | +
|
| 178 | + Parameters |
| 179 | + ========== |
| 180 | +
|
| 181 | + key |
| 182 | + Required if tree is to be instantiated with |
| 183 | + root otherwise not needed. |
| 184 | + root_data |
| 185 | + Optional, the root node of the tree. |
| 186 | + If not of type TreeNode, it will consider |
| 187 | + root as data and a new root node will |
| 188 | + be created. |
| 189 | + comp: lambda |
| 190 | + Optional, A lambda function which will be used |
| 191 | + for comparison of keys. Should return a |
| 192 | + bool value. By default it implements less |
| 193 | + than operator. |
| 194 | +
|
| 195 | + References |
| 196 | + ========== |
| 197 | +
|
| 198 | + .. [1] https://en.wikipedia.org/wiki/Tree_(data_structure)#Parent_pointer_tree |
| 199 | + """ |
| 200 | + |
| 201 | + __slots__ = ['root_idx', 'comparator', 'tree', 'size'] |
| 202 | + |
| 203 | + def __new__(cls, key=None, root_data=None, comp=None, **kwargs): |
| 204 | + raise_if_backend_is_not_python( |
| 205 | + cls, kwargs.get('backend', Backend.PYTHON)) |
| 206 | + obj = object.__new__(cls) |
| 207 | + if key is None and root_data is not None: |
| 208 | + raise ValueError('Key required.') |
| 209 | + key = None if root_data is None else key |
| 210 | + root = ParentPointerTreeNode(key, root_data) |
| 211 | + root.is_root = True |
| 212 | + obj.root_idx = 0 |
| 213 | + obj.tree, obj.size = ArrayForTrees(ParentPointerTreeNode, [root]), 1 |
| 214 | + obj.comparator = lambda key1, key2: key1 < key2 \ |
| 215 | + if comp is None else comp |
| 216 | + |
| 217 | + return obj |
| 218 | + |
| 219 | + @classmethod |
| 220 | + def methods(cls): |
| 221 | + return ['__new__', '__str__'] |
| 222 | + |
| 223 | + def insert(self, parent_key, key, data=None): |
| 224 | + """ |
| 225 | + Inserts data by the passed key using iterative |
| 226 | + algorithm. |
| 227 | +
|
| 228 | + Parameters |
| 229 | + ========== |
| 230 | +
|
| 231 | + key |
| 232 | + The key for comparison. |
| 233 | + data |
| 234 | + The data to be inserted. |
| 235 | +
|
| 236 | + Returns |
| 237 | + ======= |
| 238 | +
|
| 239 | + None |
| 240 | + """ |
| 241 | + if parent_key is None: |
| 242 | + raise ValueError("Parent key is required.") |
| 243 | + if key is None: |
| 244 | + raise ValueError("Key is required.") |
| 245 | + if self.search(key) is not None: |
| 246 | + raise ValueError("Key already exists.") |
| 247 | + |
| 248 | + parent_node = self.search(parent_key, parent=True) |
| 249 | + new_node = ParentPointerTreeNode(key, data, parent_node) |
| 250 | + |
| 251 | + self.tree.append(new_node) |
| 252 | + self.size += 1 |
| 253 | + |
| 254 | + def delete(self, key): |
| 255 | + """ |
| 256 | + Deletes the data with the passed key |
| 257 | + using iterative algorithm. |
| 258 | +
|
| 259 | + Parameters |
| 260 | + ========== |
| 261 | +
|
| 262 | + key |
| 263 | + The key of the node which is |
| 264 | + to be deleted. |
| 265 | +
|
| 266 | + Returns |
| 267 | + ======= |
| 268 | +
|
| 269 | + True |
| 270 | + If the node is deleted successfully. |
| 271 | +
|
| 272 | + None |
| 273 | + If the node to be deleted doesn't exists. |
| 274 | +
|
| 275 | + Note |
| 276 | + ==== |
| 277 | +
|
| 278 | + The node is deleted means that the connection to that |
| 279 | + node are removed but the it is still in tree. |
| 280 | + """ |
| 281 | + for idx in range(self.size): |
| 282 | + if self.tree[idx].key == key: |
| 283 | + self.tree.delete(idx) |
| 284 | + return True |
| 285 | + |
| 286 | + return None |
| 287 | + |
| 288 | + def search(self, key, **kwargs): |
| 289 | + """ |
| 290 | + Searches for the data in the tree |
| 291 | + using iterative algorithm. |
| 292 | +
|
| 293 | + Parameters |
| 294 | + ========== |
| 295 | +
|
| 296 | + key |
| 297 | + The key for searching. |
| 298 | + parent: bool |
| 299 | + If true then returns index of the |
| 300 | + parent of the node with the passed |
| 301 | + key. |
| 302 | + By default, False |
| 303 | +
|
| 304 | + Returns |
| 305 | + ======= |
| 306 | +
|
| 307 | + int |
| 308 | + If the node with the passed key is |
| 309 | + in the tree. |
| 310 | + tuple |
| 311 | + The index of the searched node and |
| 312 | + the index of the parent of that node. |
| 313 | + None |
| 314 | + In all other cases. |
| 315 | + """ |
| 316 | + |
| 317 | + |
| 318 | + def __str__(self): |
| 319 | + to_be_printed = ['' for i in range(self.tree._last_pos_filled + 1)] |
| 320 | + for i in range(self.tree._last_pos_filled + 1): |
| 321 | + if self.tree[i] is not None: |
| 322 | + node = self.tree[i] |
| 323 | + to_be_printed[i] = (node.key, node.data, node.parent) |
| 324 | + return str(to_be_printed) |
0 commit comments