Skip to content

Commit 835aeef

Browse files
authored
Added Disjoint set data structure (#143)
1 parent fbbd987 commit 835aeef

File tree

5 files changed

+130
-3
lines changed

5 files changed

+130
-3
lines changed

pydatastructs/miscellaneous_data_structures/__init__.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
from . import (
44
stack,
5-
binomial_trees
5+
binomial_trees,
6+
queue,
7+
disjoint_set
68
)
79

810
from .binomial_trees import (
@@ -19,3 +21,8 @@
1921
Queue,
2022
)
2123
__all__.extend(queue.__all__)
24+
25+
from .disjoint_set import (
26+
DisjointSetForest,
27+
)
28+
__all__.extend(disjoint_set.__all__)
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
from pydatastructs.utils import Set
2+
3+
__all__ = ['DisjointSetForest']
4+
5+
class DisjointSetForest(object):
6+
"""
7+
Represents a forest of disjoint set trees.
8+
9+
Examples
10+
========
11+
12+
>>> from pydatastructs import DisjointSetForest
13+
>>> dst = DisjointSetForest()
14+
>>> dst.make_set(1)
15+
>>> dst.make_set(2)
16+
>>> dst.union(1, 2)
17+
>>> dst.find_root(2).key
18+
1
19+
20+
References
21+
==========
22+
23+
.. [1] https://en.wikipedia.org/wiki/Disjoint-set_data_structure
24+
"""
25+
26+
__slots__ = ['tree']
27+
28+
def __new__(cls):
29+
obj = object.__new__(cls)
30+
obj.tree = dict()
31+
return obj
32+
33+
def make_set(self, key, data=None):
34+
"""
35+
Adds a singleton set to the tree
36+
of disjoint sets with given key
37+
and optionally data.
38+
"""
39+
if self.tree.get(key, None) is None:
40+
new_set = Set(key, data)
41+
self.tree[key] = new_set
42+
new_set.parent = new_set
43+
new_set.size = 1
44+
45+
def find_root(self, key):
46+
"""
47+
Finds the root of the set
48+
with the given key by path
49+
splitting algorithm.
50+
"""
51+
if self.tree.get(key, None) is None:
52+
raise KeyError("Invalid key, %s"%(key))
53+
_set = self.tree[key]
54+
while _set.parent is not _set:
55+
_set, _set.parent = _set.parent, _set.parent.parent
56+
return _set
57+
58+
def union(self, key1, key2):
59+
"""
60+
Takes the union of the two
61+
disjoint set trees with given
62+
keys. The union is done by size.
63+
"""
64+
x_root = self.find_root(key1)
65+
y_root = self.find_root(key2)
66+
67+
if x_root is not y_root:
68+
if x_root.size < y_root.size:
69+
x_root, y_root = y_root, x_root
70+
71+
y_root.parent = x_root
72+
x_root.size += y_root.size
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
from pydatastructs import DisjointSetForest
2+
from pydatastructs.utils.raises_util import raises
3+
4+
def test_DisjointSetForest():
5+
6+
dst = DisjointSetForest()
7+
for i in range(8):
8+
dst.make_set(i+1)
9+
10+
dst.union(1, 2)
11+
dst.union(1, 5)
12+
dst.union(1, 6)
13+
dst.union(1, 8)
14+
dst.union(3, 4)
15+
16+
assert (dst.find_root(1) == dst.find_root(2) ==
17+
dst.find_root(5) == dst.find_root(6) == dst.find_root(8))
18+
assert dst.find_root(3) == dst.find_root(4)
19+
assert dst.find_root(7).key == 7
20+
21+
assert raises(KeyError, lambda: dst.find_root(9))
22+
dst.union(3, 1)
23+
assert dst.find_root(3).key == 1

pydatastructs/utils/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
BinomialTreeNode,
88
AdjacencyListGraphNode,
99
AdjacencyMatrixGraphNode,
10-
GraphEdge
10+
GraphEdge,
11+
Set
1112
)
1213
__all__.extend(misc_util.__all__)

pydatastructs/utils/misc_util.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
'BinomialTreeNode',
55
'AdjacencyListGraphNode',
66
'AdjacencyMatrixGraphNode',
7-
'GraphEdge'
7+
'GraphEdge',
8+
'Set'
89
]
910

1011
_check_type = lambda a, t: isinstance(a, t)
@@ -225,3 +226,26 @@ def __new__(cls, node1, node2, value=None):
225226

226227
def __str__(self):
227228
return str((self.source.name, self.target.name))
229+
230+
class Set(object):
231+
"""
232+
Represents a set in a forest of disjoint sets.
233+
234+
Parameters
235+
==========
236+
237+
key: Hashable python object
238+
The key which uniquely identifies
239+
the set.
240+
data: Python object
241+
The data to be stored in the set.
242+
"""
243+
244+
__slots__ = ['parent', 'size', 'key', 'data']
245+
246+
def __new__(cls, key, data):
247+
obj = object.__new__(cls)
248+
obj.key = key
249+
obj.data = data
250+
obj.parent, obj.size = [None]*2
251+
return obj

0 commit comments

Comments
 (0)