1
+ //! A Union-Find (Disjoint Set) data structure implementation in Rust.
2
+ //!
3
+ //! The Union-Find data structure keeps track of elements partitioned into
4
+ //! disjoint (non-overlapping) sets.
5
+ //! It provides near-constant-time operations to add new sets, to find the
6
+ //! representative of a set, and to merge sets.
7
+
1
8
use std:: collections:: HashMap ;
2
9
use std:: fmt:: Debug ;
3
10
use std:: hash:: Hash ;
4
11
5
- /// UnionFind data structure
6
- /// It acts by holding an array of pointers to parents, together with the size of each subset
7
12
#[ derive( Debug ) ]
8
13
pub struct UnionFind < T : Debug + Eq + Hash > {
9
- payloads : HashMap < T , usize > , // we are going to manipulate indices to parent, thus `usize`. We need a map to associate a value to its index in the parent links array
10
- parent_links : Vec < usize > , // holds the relationship between an item and its parent. The root of a set is denoted by parent_links[i] == i
11
- sizes : Vec < usize > , // holds the size
12
- count : usize ,
14
+ payloads : HashMap < T , usize > , // Maps values to their indices in the parent_links array.
15
+ parent_links : Vec < usize > , // Holds the parent pointers; root elements are their own parents.
16
+ sizes : Vec < usize > , // Holds the sizes of the sets.
17
+ count : usize , // Number of disjoint sets.
13
18
}
14
19
15
20
impl < T : Debug + Eq + Hash > UnionFind < T > {
16
- /// Creates an empty Union Find structure with capacity n
17
- ///
18
- /// # Examples
19
- ///
20
- /// ```
21
- /// use the_algorithms_rust::data_structures::UnionFind;
22
- /// let uf = UnionFind::<&str>::with_capacity(5);
23
- /// assert_eq!(0, uf.count())
24
- /// ```
21
+ /// Creates an empty Union-Find structure with a specified capacity.
25
22
pub fn with_capacity ( capacity : usize ) -> Self {
26
23
Self {
27
24
parent_links : Vec :: with_capacity ( capacity) ,
@@ -31,7 +28,7 @@ impl<T: Debug + Eq + Hash> UnionFind<T> {
31
28
}
32
29
}
33
30
34
- /// Inserts a new item (disjoint) in the data structure
31
+ /// Inserts a new item (disjoint set) into the data structure.
35
32
pub fn insert ( & mut self , item : T ) {
36
33
let key = self . payloads . len ( ) ;
37
34
self . parent_links . push ( key) ;
@@ -40,107 +37,60 @@ impl<T: Debug + Eq + Hash> UnionFind<T> {
40
37
self . count += 1 ;
41
38
}
42
39
43
- pub fn id ( & self , value : & T ) -> Option < usize > {
44
- self . payloads . get ( value) . copied ( )
45
- }
46
-
47
- /// Returns the key of an item stored in the data structure or None if it doesn't exist
48
- fn find ( & self , value : & T ) -> Option < usize > {
49
- self . id ( value) . map ( |id| self . find_by_key ( id) )
40
+ /// Returns the root index of the set containing the given value, or `None` if it doesn't exist.
41
+ pub fn find ( & mut self , value : & T ) -> Option < usize > {
42
+ self . payloads
43
+ . get ( value)
44
+ . copied ( )
45
+ . map ( |key| self . find_by_key ( key) )
50
46
}
51
47
52
- /// Creates a link between value_1 and value_2
53
- /// returns None if either value_1 or value_2 hasn't been inserted in the data structure first
54
- /// returns Some(true) if two disjoint sets have been merged
55
- /// returns Some(false) if both elements already were belonging to the same set
56
- ///
57
- /// #_Examples:
58
- ///
59
- /// ```
60
- /// use the_algorithms_rust::data_structures::UnionFind;
61
- /// let mut uf = UnionFind::with_capacity(2);
62
- /// uf.insert("A");
63
- /// uf.insert("B");
64
- ///
65
- /// assert_eq!(None, uf.union(&"A", &"C"));
66
- ///
67
- /// assert_eq!(2, uf.count());
68
- /// assert_eq!(Some(true), uf.union(&"A", &"B"));
69
- /// assert_eq!(1, uf.count());
70
- ///
71
- /// assert_eq!(Some(false), uf.union(&"A", &"B"));
72
- /// ```
73
- pub fn union ( & mut self , item1 : & T , item2 : & T ) -> Option < bool > {
74
- match ( self . find ( item1) , self . find ( item2) ) {
75
- ( Some ( k1) , Some ( k2) ) => Some ( self . union_by_key ( k1, k2) ) ,
48
+ /// Unites the sets containing the two given values. Returns:
49
+ /// - `None` if either value hasn't been inserted,
50
+ /// - `Some(true)` if two disjoint sets have been merged,
51
+ /// - `Some(false)` if both elements were already in the same set.
52
+ pub fn union ( & mut self , first_item : & T , sec_item : & T ) -> Option < bool > {
53
+ let ( first_root, sec_root) = ( self . find ( first_item) , self . find ( sec_item) ) ;
54
+ match ( first_root, sec_root) {
55
+ ( Some ( first_root) , Some ( sec_root) ) => Some ( self . union_by_key ( first_root, sec_root) ) ,
76
56
_ => None ,
77
57
}
78
58
}
79
59
80
- /// Returns the parent of the element given its id
81
- fn find_by_key ( & self , key : usize ) -> usize {
82
- let mut id = key;
83
- while id != self . parent_links [ id] {
84
- id = self . parent_links [ id] ;
60
+ /// Finds the root of the set containing the element with the given index.
61
+ fn find_by_key ( & mut self , key : usize ) -> usize {
62
+ if self . parent_links [ key] != key {
63
+ self . parent_links [ key] = self . find_by_key ( self . parent_links [ key] ) ;
85
64
}
86
- id
65
+ self . parent_links [ key ]
87
66
}
88
67
89
- /// Unions the sets containing id1 and id2
90
- fn union_by_key ( & mut self , key1 : usize , key2 : usize ) -> bool {
91
- let root1 = self . find_by_key ( key1 ) ;
92
- let root2 = self . find_by_key ( key2 ) ;
93
- if root1 == root2 {
94
- return false ; // they belong to the same set already, no-op
68
+ /// Unites the sets containing the two elements identified by their indices.
69
+ fn union_by_key ( & mut self , first_key : usize , sec_key : usize ) -> bool {
70
+ let ( first_root , sec_root ) = ( self . find_by_key ( first_key ) , self . find_by_key ( sec_key ) ) ;
71
+
72
+ if first_root == sec_root {
73
+ return false ;
95
74
}
96
- // Attach the smaller set to the larger one
97
- if self . sizes [ root1 ] < self . sizes [ root2 ] {
98
- self . parent_links [ root1 ] = root2 ;
99
- self . sizes [ root2 ] += self . sizes [ root1 ] ;
75
+
76
+ if self . sizes [ first_root ] < self . sizes [ sec_root ] {
77
+ self . parent_links [ first_root ] = sec_root ;
78
+ self . sizes [ sec_root ] += self . sizes [ first_root ] ;
100
79
} else {
101
- self . parent_links [ root2 ] = root1 ;
102
- self . sizes [ root1 ] += self . sizes [ root2 ] ;
80
+ self . parent_links [ sec_root ] = first_root ;
81
+ self . sizes [ first_root ] += self . sizes [ sec_root ] ;
103
82
}
104
- self . count -= 1 ; // we had 2 disjoint sets, now merged as one
83
+
84
+ self . count -= 1 ;
105
85
true
106
86
}
107
87
108
- /// Checks if two items belong to the same set
109
- ///
110
- /// #_Examples:
111
- ///
112
- /// ```
113
- /// use the_algorithms_rust::data_structures::UnionFind;
114
- /// let mut uf = UnionFind::from_iter(["A", "B"]);
115
- /// assert!(!uf.is_same_set(&"A", &"B"));
116
- ///
117
- /// uf.union(&"A", &"B");
118
- /// assert!(uf.is_same_set(&"A", &"B"));
119
- ///
120
- /// assert!(!uf.is_same_set(&"A", &"C"));
121
- /// ```
122
- pub fn is_same_set ( & self , item1 : & T , item2 : & T ) -> bool {
123
- matches ! ( ( self . find( item1) , self . find( item2) ) , ( Some ( root1) , Some ( root2) ) if root1 == root2)
88
+ /// Checks if two items belong to the same set.
89
+ pub fn is_same_set ( & mut self , first_item : & T , sec_item : & T ) -> bool {
90
+ matches ! ( ( self . find( first_item) , self . find( sec_item) ) , ( Some ( first_root) , Some ( sec_root) ) if first_root == sec_root)
124
91
}
125
92
126
- /// Returns the number of disjoint sets
127
- ///
128
- /// # Examples
129
- ///
130
- /// ```
131
- /// use the_algorithms_rust::data_structures::UnionFind;
132
- /// let mut uf = UnionFind::with_capacity(5);
133
- /// assert_eq!(0, uf.count());
134
- ///
135
- /// uf.insert("A");
136
- /// assert_eq!(1, uf.count());
137
- ///
138
- /// uf.insert("B");
139
- /// assert_eq!(2, uf.count());
140
- ///
141
- /// uf.union(&"A", &"B");
142
- /// assert_eq!(1, uf.count())
143
- /// ```
93
+ /// Returns the number of disjoint sets.
144
94
pub fn count ( & self ) -> usize {
145
95
self . count
146
96
}
@@ -158,11 +108,11 @@ impl<T: Debug + Eq + Hash> Default for UnionFind<T> {
158
108
}
159
109
160
110
impl < T : Debug + Eq + Hash > FromIterator < T > for UnionFind < T > {
161
- /// Creates a new UnionFind data structure from an iterable of disjoint elements
111
+ /// Creates a new UnionFind data structure from an iterable of disjoint elements.
162
112
fn from_iter < I : IntoIterator < Item = T > > ( iter : I ) -> Self {
163
113
let mut uf = UnionFind :: default ( ) ;
164
- for i in iter {
165
- uf. insert ( i ) ;
114
+ for item in iter {
115
+ uf. insert ( item ) ;
166
116
}
167
117
uf
168
118
}
@@ -175,45 +125,100 @@ mod tests {
175
125
#[ test]
176
126
fn test_union_find ( ) {
177
127
let mut uf = UnionFind :: from_iter ( 0 ..10 ) ;
178
- assert_eq ! ( uf. find_by_key( 0 ) , 0 ) ;
179
- assert_eq ! ( uf. find_by_key( 1 ) , 1 ) ;
180
- assert_eq ! ( uf. find_by_key( 2 ) , 2 ) ;
181
- assert_eq ! ( uf. find_by_key( 3 ) , 3 ) ;
182
- assert_eq ! ( uf. find_by_key( 4 ) , 4 ) ;
183
- assert_eq ! ( uf. find_by_key( 5 ) , 5 ) ;
184
- assert_eq ! ( uf. find_by_key( 6 ) , 6 ) ;
185
- assert_eq ! ( uf. find_by_key( 7 ) , 7 ) ;
186
- assert_eq ! ( uf. find_by_key( 8 ) , 8 ) ;
187
- assert_eq ! ( uf. find_by_key( 9 ) , 9 ) ;
188
-
189
- assert_eq ! ( Some ( true ) , uf. union ( & 0 , & 1 ) ) ;
190
- assert_eq ! ( Some ( true ) , uf. union ( & 1 , & 2 ) ) ;
191
- assert_eq ! ( Some ( true ) , uf. union ( & 2 , & 3 ) ) ;
128
+ assert_eq ! ( uf. find( & 0 ) , Some ( 0 ) ) ;
129
+ assert_eq ! ( uf. find( & 1 ) , Some ( 1 ) ) ;
130
+ assert_eq ! ( uf. find( & 2 ) , Some ( 2 ) ) ;
131
+ assert_eq ! ( uf. find( & 3 ) , Some ( 3 ) ) ;
132
+ assert_eq ! ( uf. find( & 4 ) , Some ( 4 ) ) ;
133
+ assert_eq ! ( uf. find( & 5 ) , Some ( 5 ) ) ;
134
+ assert_eq ! ( uf. find( & 6 ) , Some ( 6 ) ) ;
135
+ assert_eq ! ( uf. find( & 7 ) , Some ( 7 ) ) ;
136
+ assert_eq ! ( uf. find( & 8 ) , Some ( 8 ) ) ;
137
+ assert_eq ! ( uf. find( & 9 ) , Some ( 9 ) ) ;
138
+
139
+ assert ! ( !uf. is_same_set( & 0 , & 1 ) ) ;
140
+ assert ! ( !uf. is_same_set( & 2 , & 9 ) ) ;
141
+ assert_eq ! ( uf. count( ) , 10 ) ;
142
+
143
+ assert_eq ! ( uf. union ( & 0 , & 1 ) , Some ( true ) ) ;
144
+ assert_eq ! ( uf. union ( & 1 , & 2 ) , Some ( true ) ) ;
145
+ assert_eq ! ( uf. union ( & 2 , & 3 ) , Some ( true ) ) ;
146
+ assert_eq ! ( uf. union ( & 0 , & 2 ) , Some ( false ) ) ;
147
+ assert_eq ! ( uf. union ( & 4 , & 5 ) , Some ( true ) ) ;
148
+ assert_eq ! ( uf. union ( & 5 , & 6 ) , Some ( true ) ) ;
149
+ assert_eq ! ( uf. union ( & 6 , & 7 ) , Some ( true ) ) ;
150
+ assert_eq ! ( uf. union ( & 7 , & 8 ) , Some ( true ) ) ;
151
+ assert_eq ! ( uf. union ( & 8 , & 9 ) , Some ( true ) ) ;
152
+ assert_eq ! ( uf. union ( & 7 , & 9 ) , Some ( false ) ) ;
153
+
154
+ assert_ne ! ( uf. find( & 0 ) , uf. find( & 9 ) ) ;
155
+ assert_eq ! ( uf. find( & 0 ) , uf. find( & 3 ) ) ;
156
+ assert_eq ! ( uf. find( & 4 ) , uf. find( & 9 ) ) ;
157
+ assert ! ( uf. is_same_set( & 0 , & 3 ) ) ;
158
+ assert ! ( uf. is_same_set( & 4 , & 9 ) ) ;
159
+ assert ! ( !uf. is_same_set( & 0 , & 9 ) ) ;
160
+ assert_eq ! ( uf. count( ) , 2 ) ;
161
+
192
162
assert_eq ! ( Some ( true ) , uf. union ( & 3 , & 4 ) ) ;
193
- assert_eq ! ( Some ( true ) , uf. union ( & 4 , & 5 ) ) ;
194
- assert_eq ! ( Some ( true ) , uf. union ( & 5 , & 6 ) ) ;
195
- assert_eq ! ( Some ( true ) , uf. union ( & 6 , & 7 ) ) ;
196
- assert_eq ! ( Some ( true ) , uf. union ( & 7 , & 8 ) ) ;
197
- assert_eq ! ( Some ( true ) , uf. union ( & 8 , & 9 ) ) ;
198
- assert_eq ! ( Some ( false ) , uf. union ( & 9 , & 0 ) ) ;
199
-
200
- assert_eq ! ( 1 , uf. count( ) ) ;
163
+ assert_eq ! ( uf. find( & 0 ) , uf. find( & 9 ) ) ;
164
+ assert_eq ! ( uf. count( ) , 1 ) ;
165
+ assert ! ( uf. is_same_set( & 0 , & 9 ) ) ;
166
+
167
+ assert_eq ! ( None , uf. union ( & 0 , & 11 ) ) ;
201
168
}
202
169
203
170
#[ test]
204
171
fn test_spanning_tree ( ) {
205
- // Let's imagine the following topology:
206
- // A <-> B
207
- // B <-> C
208
- // A <-> D
209
- // E
210
- // F <-> G
211
- // We have 3 disjoint sets: {A, B, C, D}, {E}, {F, G}
212
172
let mut uf = UnionFind :: from_iter ( [ "A" , "B" , "C" , "D" , "E" , "F" , "G" ] ) ;
213
173
uf. union ( & "A" , & "B" ) ;
214
174
uf. union ( & "B" , & "C" ) ;
215
175
uf. union ( & "A" , & "D" ) ;
216
176
uf. union ( & "F" , & "G" ) ;
217
- assert_eq ! ( 3 , uf. count( ) ) ;
177
+
178
+ assert_eq ! ( None , uf. union ( & "A" , & "W" ) ) ;
179
+
180
+ assert_eq ! ( uf. find( & "A" ) , uf. find( & "B" ) ) ;
181
+ assert_eq ! ( uf. find( & "A" ) , uf. find( & "C" ) ) ;
182
+ assert_eq ! ( uf. find( & "B" ) , uf. find( & "D" ) ) ;
183
+ assert_ne ! ( uf. find( & "A" ) , uf. find( & "E" ) ) ;
184
+ assert_ne ! ( uf. find( & "A" ) , uf. find( & "F" ) ) ;
185
+ assert_eq ! ( uf. find( & "G" ) , uf. find( & "F" ) ) ;
186
+ assert_ne ! ( uf. find( & "G" ) , uf. find( & "E" ) ) ;
187
+
188
+ assert ! ( uf. is_same_set( & "A" , & "B" ) ) ;
189
+ assert ! ( uf. is_same_set( & "A" , & "C" ) ) ;
190
+ assert ! ( uf. is_same_set( & "B" , & "D" ) ) ;
191
+ assert ! ( !uf. is_same_set( & "B" , & "F" ) ) ;
192
+ assert ! ( !uf. is_same_set( & "E" , & "A" ) ) ;
193
+ assert ! ( !uf. is_same_set( & "E" , & "G" ) ) ;
194
+ assert_eq ! ( uf. count( ) , 3 ) ;
195
+ }
196
+
197
+ #[ test]
198
+ fn test_with_capacity ( ) {
199
+ let mut uf: UnionFind < i32 > = UnionFind :: with_capacity ( 5 ) ;
200
+ uf. insert ( 0 ) ;
201
+ uf. insert ( 1 ) ;
202
+ uf. insert ( 2 ) ;
203
+ uf. insert ( 3 ) ;
204
+ uf. insert ( 4 ) ;
205
+
206
+ assert_eq ! ( uf. count( ) , 5 ) ;
207
+
208
+ assert_eq ! ( uf. union ( & 0 , & 1 ) , Some ( true ) ) ;
209
+ assert ! ( uf. is_same_set( & 0 , & 1 ) ) ;
210
+ assert_eq ! ( uf. count( ) , 4 ) ;
211
+
212
+ assert_eq ! ( uf. union ( & 2 , & 3 ) , Some ( true ) ) ;
213
+ assert ! ( uf. is_same_set( & 2 , & 3 ) ) ;
214
+ assert_eq ! ( uf. count( ) , 3 ) ;
215
+
216
+ assert_eq ! ( uf. union ( & 0 , & 2 ) , Some ( true ) ) ;
217
+ assert ! ( uf. is_same_set( & 0 , & 1 ) ) ;
218
+ assert ! ( uf. is_same_set( & 2 , & 3 ) ) ;
219
+ assert ! ( uf. is_same_set( & 0 , & 3 ) ) ;
220
+ assert_eq ! ( uf. count( ) , 2 ) ;
221
+
222
+ assert_eq ! ( None , uf. union ( & 0 , & 10 ) ) ;
218
223
}
219
224
}
0 commit comments