diff --git a/pydatastructs/trees/__init__.py b/pydatastructs/trees/__init__.py index c9dc298cb..42f919c35 100644 --- a/pydatastructs/trees/__init__.py +++ b/pydatastructs/trees/__init__.py @@ -2,6 +2,7 @@ from . import ( binary_trees, + m_ary_trees, space_partitioning_trees, heaps ) @@ -15,6 +16,12 @@ ) __all__.extend(binary_trees.__all__) +from .m_ary_trees import ( + MAryTreeNode, MAryTree +) + +__all__.extend(m_ary_trees.__all__) + from .space_partitioning_trees import ( OneDimensionalSegmentTree ) diff --git a/pydatastructs/trees/m_ary_trees.py b/pydatastructs/trees/m_ary_trees.py new file mode 100644 index 000000000..f0a4d389a --- /dev/null +++ b/pydatastructs/trees/m_ary_trees.py @@ -0,0 +1,162 @@ +from pydatastructs.utils import MAryTreeNode +from pydatastructs.linear_data_structures.arrays import ArrayForTrees + +__all__ = [ + 'MAryTree' +] + +class MAryTree(object): + """ + Abstract m-ary tree. + + Parameters + ========== + + root_data + Optional, the root node of the binary tree. + If not of type MAryTreeNode, it will consider + root as data and a new root node will + be created. + key + Required if tree is to be instantiated with + root otherwise not needed. + comp: lambda + Optional, A lambda function which will be used + for comparison of keys. Should return a + bool value. By default it implements less + than operator. + is_order_statistic: bool + Set it to True, if you want to use the + order statistic features of the tree. + max_children + Optional, specifies the maximum number of children + a node can have. Defaults to 2 in case nothing is + specified. + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/M-ary_tree + """ + + __slots__ = ['root_idx', 'max_children', 'comparator', 'tree', 'size', + 'is_order_statistic'] + + + def __new__(cls, key=None, root_data=None, comp=None, + is_order_statistic=False, max_children=2): + obj = object.__new__(cls) + if key is None and root_data is not None: + raise ValueError('Key required.') + key = None if root_data is None else key + root = MAryTreeNode(key, root_data) + root.is_root = True + obj.root_idx = 0 + obj.max_children = max_children + obj.tree, obj.size = ArrayForTrees(MAryTreeNode, [root]), 1 + obj.comparator = lambda key1, key2: key1 < key2 \ + if comp is None else comp + obj.is_order_statistic = is_order_statistic + return obj + + def insert(self, key, data): + """ + Inserts data by the passed key using iterative + algorithm. + + Parameters + ========== + + key + The key for comparison. + data + The data to be inserted. + + Returns + ======= + + None + """ + raise NotImplementedError("This is an abstract method.") + + def delete(self, key, **kwargs): + """ + Deletes the data with the passed key + using iterative algorithm. + + Parameters + ========== + + key + The key of the node which is + to be deleted. + + Returns + ======= + + True + If the node is deleted successfully. + None + If the node to be deleted doesn't exists. + + Note + ==== + + The node is deleted means that the connection to that + node are removed but the it is still in tree. + """ + raise NotImplementedError("This is an abstract method.") + + def search(self, key, **kwargs): + """ + Searches for the data in the binary search tree + using iterative algorithm. + + Parameters + ========== + + key + The key for searching. + parent: bool + If true then returns index of the + parent of the node with the passed + key. + By default, False + + Returns + ======= + + int + If the node with the passed key is + in the tree. + tuple + The index of the searched node and + the index of the parent of that node. + None + In all other cases. + """ + raise NotImplementedError("This is an abstract method.") + + def to_binary_tree(self): + """ + Converts an m-ary tree to a binary tree. + + Returns + ======= + + TreeNode + The root of the newly created binary tree. + """ + raise NotImplementedError("This is an abstract method.") + + + def __str__(self): + to_be_printed = ['' for i in range(self.tree._last_pos_filled + 1)] + for i in range(self.tree._last_pos_filled + 1): + if self.tree[i] is not None: + node = self.tree[i] + to_be_printed[i] = (node.key, node.data) + for j in node.children: + if j is not None: + to_be_printed[i].append(j) + return str(to_be_printed) diff --git a/pydatastructs/utils/__init__.py b/pydatastructs/utils/__init__.py index bb63db83e..a59e4a3dc 100644 --- a/pydatastructs/utils/__init__.py +++ b/pydatastructs/utils/__init__.py @@ -3,6 +3,7 @@ from . import misc_util from .misc_util import ( TreeNode, + MAryTreeNode, LinkedListNode, BinomialTreeNode, AdjacencyListGraphNode, diff --git a/pydatastructs/utils/misc_util.py b/pydatastructs/utils/misc_util.py index 6319c19bd..a573a86f5 100644 --- a/pydatastructs/utils/misc_util.py +++ b/pydatastructs/utils/misc_util.py @@ -1,5 +1,6 @@ __all__ = [ 'TreeNode', + 'MAryTreeNode', 'LinkedListNode', 'BinomialTreeNode', 'AdjacencyListGraphNode', @@ -104,6 +105,49 @@ def __str__(self): """ return str((self.key, self.data)) +class MAryTreeNode(TreeNode): + """ + Represents node in an M-ary trees. + + Parameters + ========== + + data + Any valid data to be stored in the node. + key + Required for comparison operations. + + Note + ==== + + The following are the data members of the class: + + children: DynamicOneDimensionalArray + An array of indices which stores the children of + this node in the M-ary tree array + is_root: bool, by default, False + If the current node is a root of the tree then + set it to True otherwise False. + """ + __slots__ = ['key', 'children', 'data', 'is_root'] + + def __new__(cls, key, data): + from pydatastructs.linear_data_structures.arrays import DynamicOneDimensionalArray + obj = Node.__new__(cls) + obj.data = data + obj.key = key + obj.is_root = False + obj.children = DynamicOneDimensionalArray(int, 0) + return obj + + def add_children(self, *children): + """ + Adds children of current node. + """ + for child in children: + self.children.append(child) + + class LinkedListNode(Node): """ Represents node in linked lists.