Skip to content

Commit d889f2a

Browse files
authored
Implemeted Treaps and CartesianTree (#235)
1 parent 9a4e70b commit d889f2a

File tree

7 files changed

+237
-6
lines changed

7 files changed

+237
-6
lines changed

pydatastructs/trees/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
BinaryTreeTraversal,
1414
AVLTree,
1515
BinaryIndexedTree,
16+
CartesianTree,
17+
Treap,
1618
SplayTree
1719
)
1820
__all__.extend(binary_trees.__all__)

pydatastructs/trees/binary_trees.py

Lines changed: 141 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
from pydatastructs.utils import TreeNode
1+
from pydatastructs.utils import TreeNode, CartesianTreeNode
22
from pydatastructs.miscellaneous_data_structures import Stack
33
from pydatastructs.linear_data_structures import (
44
OneDimensionalArray, DynamicOneDimensionalArray)
55
from pydatastructs.linear_data_structures.arrays import ArrayForTrees
66
from collections import deque as Queue
7+
import random
78
from copy import deepcopy
89

910
__all__ = [
@@ -12,6 +13,8 @@
1213
'BinarySearchTree',
1314
'BinaryTreeTraversal',
1415
'BinaryIndexedTree',
16+
'CartesianTree',
17+
'Treap',
1518
'SplayTree'
1619
]
1720

@@ -642,6 +645,143 @@ def _left_rotate(self, j, k):
642645
if kp is None:
643646
self.root_idx = k
644647

648+
class CartesianTree(SelfBalancingBinaryTree):
649+
"""
650+
Represents cartesian trees.
651+
652+
Examples
653+
========
654+
655+
>>> from pydatastructs.trees import CartesianTree as CT
656+
>>> c = CT()
657+
>>> c.insert(1, 4, 1)
658+
>>> c.insert(2, 3, 2)
659+
>>> child = c.tree[c.root_idx].left
660+
>>> c.tree[child].data
661+
1
662+
>>> c.search(1)
663+
0
664+
>>> c.search(-1) is None
665+
True
666+
>>> c.delete(1) is True
667+
True
668+
>>> c.search(1) is None
669+
True
670+
>>> c.delete(2) is True
671+
True
672+
>>> c.search(2) is None
673+
True
674+
675+
References
676+
==========
677+
678+
.. [1] https://www.cs.princeton.edu/courses/archive/spr09/cos423/Lectures/geo-st.pdf
679+
680+
See Also
681+
========
682+
683+
pydatastructs.trees.binary_tree.SelfBalancingBinaryTree
684+
"""
685+
@classmethod
686+
def methods(cls):
687+
return ['__str__', 'insert', 'delete']
688+
689+
def _bubble_up(self, node_idx):
690+
node = self.tree[node_idx]
691+
parent_idx = self.tree[node_idx].parent
692+
parent = self.tree[parent_idx]
693+
while (node.parent is not None) and (parent.priority > node.priority):
694+
if parent.right == node_idx:
695+
self._left_rotate(parent_idx, node_idx)
696+
else:
697+
self._right_rotate(parent_idx, node_idx)
698+
node = self.tree[node_idx]
699+
parent_idx = self.tree[node_idx].parent
700+
if parent_idx is not None:
701+
parent = self.tree[parent_idx]
702+
if node.parent is None:
703+
self.tree[node_idx].is_root = True
704+
705+
def _trickle_down(self, node_idx):
706+
node = self.tree[node_idx]
707+
while node.left is not None or node.right is not None:
708+
if node.left is None:
709+
self._left_rotate(node_idx, self.tree[node_idx].right)
710+
elif node.right is None:
711+
self._right_rotate(node_idx, self.tree[node_idx].left)
712+
elif self.tree[node.left].priority < self.tree[node.right].priority:
713+
self._right_rotate(node_idx, self.tree[node_idx].left)
714+
else:
715+
self._left_rotate(node_idx, self.tree[node_idx].right)
716+
node = self.tree[node_idx]
717+
718+
def insert(self, key, priority, data=None):
719+
super(CartesianTree, self).insert(key, data)
720+
node_idx = super(CartesianTree, self).search(key)
721+
node = self.tree[node_idx]
722+
new_node = CartesianTreeNode(key, priority, data)
723+
new_node.parent = node.parent
724+
new_node.left = node.left
725+
new_node.right = node.right
726+
self.tree[node_idx] = new_node
727+
if node.is_root:
728+
self.tree[node_idx].is_root = True
729+
else:
730+
self._bubble_up(node_idx)
731+
732+
def delete(self, key, **kwargs):
733+
balancing_info = kwargs.get('balancing_info', False)
734+
node_idx = super(CartesianTree, self).search(key)
735+
if node_idx is not None:
736+
self._trickle_down(node_idx)
737+
return super(CartesianTree, self).delete(key, balancing_info = balancing_info)
738+
739+
def __str__(self):
740+
to_be_printed = ['' for i in range(self.tree._last_pos_filled + 1)]
741+
for i in range(self.tree._last_pos_filled + 1):
742+
if self.tree[i] is not None:
743+
node = self.tree[i]
744+
to_be_printed[i] = (node.left, node.key, node.priority, node.data, node.right)
745+
return str(to_be_printed)
746+
747+
class Treap(CartesianTree):
748+
"""
749+
Represents treaps.
750+
751+
Examples
752+
========
753+
754+
>>> from pydatastructs.trees import Treap as T
755+
>>> t = T()
756+
>>> t.insert(1, 1)
757+
>>> t.insert(2, 2)
758+
>>> t.search(1)
759+
0
760+
>>> t.search(-1) is None
761+
True
762+
>>> t.delete(1) is True
763+
True
764+
>>> t.search(1) is None
765+
True
766+
>>> t.delete(2) is True
767+
True
768+
>>> t.search(2) is None
769+
True
770+
771+
References
772+
==========
773+
774+
.. [1] https://en.wikipedia.org/wiki/Treap
775+
776+
"""
777+
@classmethod
778+
def methods(cls):
779+
return ['insert']
780+
781+
def insert(self, key, data=None):
782+
priority = random.random()
783+
super(Treap, self).insert(key, priority, data)
784+
645785
class AVLTree(SelfBalancingBinaryTree):
646786
"""
647787
Represents AVL trees.

pydatastructs/trees/tests/test_binary_trees.py

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
from pydatastructs.trees.binary_trees import (
22
BinarySearchTree, BinaryTreeTraversal, AVLTree,
3-
ArrayForTrees, BinaryIndexedTree, SelfBalancingBinaryTree, SplayTree)
3+
ArrayForTrees, BinaryIndexedTree, SelfBalancingBinaryTree, SplayTree, CartesianTree, Treap)
44
from pydatastructs.utils.raises_util import raises
55
from pydatastructs.utils.misc_util import TreeNode
66
from copy import deepcopy
7+
import random
78

89
def test_BinarySearchTree():
910
BST = BinarySearchTree
@@ -320,6 +321,59 @@ def test_BinaryIndexedTree():
320321
assert t.get_sum(0, 4) == 114
321322
assert t.get_sum(1, 9) == 54
322323

324+
def test_CartesianTree():
325+
tree = CartesianTree()
326+
tree.insert(3, 1, 3)
327+
tree.insert(1, 6, 1)
328+
tree.insert(0, 9, 0)
329+
tree.insert(5, 11, 5)
330+
tree.insert(4, 14, 4)
331+
tree.insert(9, 17, 9)
332+
tree.insert(7, 22, 7)
333+
tree.insert(6, 42, 6)
334+
tree.insert(8, 49, 8)
335+
tree.insert(2, 99, 2)
336+
assert str(tree) == \
337+
("[(1, 3, 1, 3, 3), (2, 1, 6, 1, 9), "
338+
"(None, 0, 9, 0, None), (4, 5, 11, 5, 5), "
339+
"(None, 4, 14, 4, None), (6, 9, 17, 9, None), "
340+
"(7, 7, 22, 7, 8), (None, 6, 42, 6, None), "
341+
"(None, 8, 49, 8, None), (None, 2, 99, 2, None)]")
342+
tree.insert(1.5, 4, 1.5)
343+
assert str(tree) == \
344+
("[(10, 3, 1, 3, 3), (2, 1, 6, 1, None), "
345+
"(None, 0, 9, 0, None), (4, 5, 11, 5, 5), "
346+
"(None, 4, 14, 4, None), (6, 9, 17, 9, None), "
347+
"(7, 7, 22, 7, 8), (None, 6, 42, 6, None), "
348+
"(None, 8, 49, 8, None), (None, 2, 99, 2, None), "
349+
"(1, 1.5, 4, 1.5, 9)]")
350+
k = tree.search(1.5)
351+
assert tree.tree[tree.tree[k].parent].key == 3
352+
tree.delete(1.5)
353+
tree.tree[tree.tree[tree.root_idx].left].key == 1
354+
tree.delete(8)
355+
assert tree.search(8) is None
356+
tree.delete(7)
357+
assert tree.search(7) is None
358+
tree.delete(3)
359+
assert tree.search(3) is None
360+
assert tree.delete(18) is None
361+
362+
def test_Treap():
363+
364+
random.seed(0)
365+
tree = Treap()
366+
tree.insert(7, 7)
367+
tree.insert(2, 2)
368+
tree.insert(3, 3)
369+
tree.insert(4, 4)
370+
tree.insert(5, 5)
371+
assert isinstance(tree.tree[0].priority, float)
372+
tree.delete(1)
373+
assert tree.search(1) is None
374+
assert tree.search(2) == 1
375+
assert tree.delete(1) is None
376+
323377
def test_issue_234():
324378
"""
325379
https://github.com/codezonediitj/pydatastructs/issues/234

pydatastructs/utils/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
AdjacencyListGraphNode,
1010
AdjacencyMatrixGraphNode,
1111
GraphEdge,
12-
Set
12+
Set,
13+
CartesianTreeNode
1314
)
1415
__all__.extend(misc_util.__all__)

pydatastructs/utils/misc_util.py

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
'AdjacencyListGraphNode',
77
'AdjacencyMatrixGraphNode',
88
'GraphEdge',
9-
'Set'
9+
'Set',
10+
'CartesianTreeNode'
1011
]
1112

1213
_check_type = lambda a, t: isinstance(a, t)
@@ -56,6 +57,34 @@ def __str__(self):
5657
"""
5758
return str((self.left, self.key, self.data, self.right))
5859

60+
class CartesianTreeNode(TreeNode):
61+
"""
62+
Represents node in cartesian trees.
63+
64+
Parameters
65+
==========
66+
67+
data
68+
Any valid data to be stored in the node.
69+
key
70+
Required for comparison operations.
71+
priority: int
72+
An integer value for heap property.
73+
74+
"""
75+
__slots__ = ['key', 'data', 'priority']
76+
77+
def __new__(cls, key, priority, data=None):
78+
obj = TreeNode.__new__(cls, key, data)
79+
obj.priority = priority
80+
return obj
81+
82+
def __str__(self):
83+
"""
84+
Used for printing.
85+
"""
86+
return str((self.left, self.key, self.priority, self.data, self.right))
87+
5988
class BinomialTreeNode(TreeNode):
6089
"""
6190
Represents node in binomial trees.

pydatastructs/utils/tests/test_code_quality.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,8 @@ def _apis():
9595
pyds.miscellaneous_data_structures.stack.LinkedListStack,
9696
pyds.DisjointSetForest, pyds.BinomialTree, pyds.TreeNode, pyds.MAryTreeNode,
9797
pyds.LinkedListNode, pyds.BinomialTreeNode, pyds.AdjacencyListGraphNode,
98-
pyds.AdjacencyMatrixGraphNode, pyds.GraphEdge, pyds.Set, pyds.BinaryIndexedTree]
98+
pyds.AdjacencyMatrixGraphNode, pyds.GraphEdge, pyds.Set, pyds.BinaryIndexedTree,
99+
pyds.CartesianTree, pyds.CartesianTreeNode, pyds.Treap]
99100

100101
def test_public_api():
101102
pyds = pydatastructs

pydatastructs/utils/tests/test_misc_util.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from pydatastructs.utils import (AdjacencyListGraphNode, AdjacencyMatrixGraphNode,
2-
GraphEdge, BinomialTreeNode, MAryTreeNode)
2+
GraphEdge, BinomialTreeNode, MAryTreeNode, CartesianTreeNode)
33
from pydatastructs.utils.raises_util import raises
44

55
def test_AdjacencyListGraphNode():
@@ -38,3 +38,7 @@ def test_MAryTreeNode():
3838
m.add_children(*[i for i in range(2,10)])
3939
assert str(m) == "(1, 1)"
4040
assert str(m.children) == "['2', '3', '4', '5', '6', '7', '8', '9']"
41+
42+
def test_CartesianTreeNode():
43+
c = CartesianTreeNode(1, 1, 1)
44+
assert str(c) == "(None, 1, 1, 1, None)"

0 commit comments

Comments
 (0)