1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # This file is free software, which comes along with NIT. This software is
4 # distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
5 # without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
6 # PARTICULAR PURPOSE. You can modify it is you want, provided this header
7 # is kept unaltered, and a notification of the changes is added.
8 # You are allowed to redistribute it and sell it, alone or is a part of
11 # union–find algorithm using an efficient disjoint-set data structure
14 import hash_collection
16 # Data structure to keeps track of elements partitioned into disjoint subsets
17 # var s = new DisjointSet[Int]
20 # assert not s.in_same_subset(1,2)
22 # assert s.in_same_subset(1,2)
24 # `in_same_subset` is transitive, reflexive and symetric
27 # assert not s.in_same_subset(1,3)
29 # assert s.in_same_subset(1,3)
31 # Unkike theorical Disjoint-set data structures, the underling implementation is opaque
32 # that makes the traditionnal `find` method unavailable for clients.
33 # The methods `in_same_subset`, `to_partitions`, and their variations are offered instead.
35 super SimpleCollection[E
]
37 # The node in the hiearchical structure for each element
38 private var nodes
= new HashMap[E
, DisjointSetNode]
40 # The number of subsets in the partition
42 # var s = new DisjointSet[Int]
43 # s.add_all([1,2,3,4,5])
44 # assert s.number_of_subsets == 5
45 # s.union_all([1,4,5])
46 # assert s.number_of_subsets == 3
48 # assert s.number_of_subsets == 3
49 var number_of_subsets
: Int = 0
51 # Get the root node of an element
53 private fun find
(e
:E
): DisjointSetNode
55 assert nodes
.has_key
(e
)
57 if ne
.parent
== ne
then return ne
63 # Get the root node of a node
64 # Use *path compression* to flatten the structure
65 # ENSURE: `result.parent == result`
66 private fun nfind
(ne
: DisjointSetNode): DisjointSetNode
69 if nf
== ne
then return ne
75 # Is the element in the structure
77 # var s = new DisjointSet[Int]
82 redef fun has
(e
: E
): Bool
84 return nodes
.has_key
(e
)
87 redef fun iterator
do return nodes
.keys
.iterator
89 # Add a new element in the structure.
90 # Initially it is in its own disjoint subset
95 if nodes
.has_key
(e
) then return
96 var ne
= new DisjointSetNode
98 number_of_subsets
+= 1
101 # Are two elements in the same subset?
102 fun in_same_subset
(e
,f
:E
): Bool
104 return e
== f
or find
(e
) == find
(f
)
107 # Are all elements of `es` in the same subset?
108 # var s = new DisjointSet[Int]
109 # s.add_all([1,2,3,4,5,6])
110 # s.union_all([1,2,3])
111 # assert not s.all_in_same_subset([2,3,4])
112 # s.union_all([1,4,5])
113 # assert s.all_in_same_subset([2,3,4])
114 fun all_in_same_subset
(es
: Collection[E
]): Bool
116 if es
.is_empty
then return true
117 var nf
= find
(es
.first
)
120 if ne
!= nf
then return false
125 # Construct the current partitionning
127 # var s = new DisjointSet[Int]
128 # s.add_all([1,2,3,4,5,6])
132 # var p = s.to_partitions
133 # assert p.length == 3
134 fun to_partitions
: Collection[Set[E
]]
136 return to_subpartition
(self)
139 # Construct a partitionning on `es`, a subset of elements
141 # var s = new DisjointSet[Int]
142 # s.add_all([1,2,3,4,5,6])
146 # var p = s.to_subpartition([1,2,4])
147 # assert p.length == 2
148 fun to_subpartition
(es
: Collection[E
]): Collection[Set[E
]]
150 var map
= new HashMap[DisjointSetNode, Set[E
]]
153 var set
= map
.get_or_null
(ne
)
163 # Combine the subsets of `e` and `f`
164 # ENSURE: `in_same_subset(e,f)`
169 if ne
== nf
then return
171 # merge them using *union by rank*
172 # attach the smaller tree to the root of the deeper tree
182 # The only case where the deep is increased is when both are equals
186 number_of_subsets
-= 1
189 # Combine the subsets of all elements of `es`
190 # ENSURE: `all_in_same_subset(cs)`
191 fun union_all
(es
:Collection[E
])
193 if es
.is_empty
then return
195 for e
in es
do union
(e
,f
)
199 # A node in the hierarchical representation of subsets
200 private class DisjointSetNode
201 # If parent == self then the node is a root
202 var parent
: DisjointSetNode = self
204 # The rank to no desequilibrate the structure.
205 # The term rank is used instead of depth since
206 # path compression is used, see `DisjointSet::nfind`