Coverage Report

Created: 2025-11-16 07:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/petgraph-0.8.3/src/unionfind.rs
Line
Count
Source
1
//! `UnionFind<K>` is a disjoint-set data structure.
2
3
use super::graph::IndexType;
4
use alloc::{collections::TryReserveError, vec, vec::Vec};
5
use core::cmp::Ordering;
6
7
/// `UnionFind<K>` is a disjoint-set data structure. It tracks set membership of *n* elements
8
/// indexed from *0* to *n - 1*. The scalar type is `K` which must be an unsigned integer type.
9
///
10
/// <http://en.wikipedia.org/wiki/Disjoint-set_data_structure>
11
///
12
/// Too awesome not to quote:
13
///
14
/// “The amortized time per operation is **O(α(n))** where **α(n)** is the
15
/// inverse of **f(x) = A(x, x)** with **A** being the extremely fast-growing Ackermann function.”
16
#[derive(Debug, Clone)]
17
pub struct UnionFind<K> {
18
    // For element at index *i*, store the index of its parent; the representative itself
19
    // stores its own index. This forms equivalence classes which are the disjoint sets, each
20
    // with a unique representative.
21
    parent: Vec<K>,
22
    // It is a balancing tree structure,
23
    // so the ranks are logarithmic in the size of the container -- a byte is more than enough.
24
    //
25
    // Rank is separated out both to save space and to save cache in when searching in the parent
26
    // vector.
27
    rank: Vec<u8>,
28
}
29
30
impl<K> Default for UnionFind<K> {
31
0
    fn default() -> Self {
32
0
        Self {
33
0
            parent: Vec::new(),
34
0
            rank: Vec::new(),
35
0
        }
36
0
    }
37
}
38
39
#[inline]
40
0
unsafe fn get_unchecked<K>(xs: &[K], index: usize) -> &K {
41
0
    debug_assert!(index < xs.len());
42
0
    xs.get_unchecked(index)
43
0
}
44
45
#[inline]
46
0
unsafe fn get_unchecked_mut<K>(xs: &mut [K], index: usize) -> &mut K {
47
0
    debug_assert!(index < xs.len());
48
0
    xs.get_unchecked_mut(index)
49
0
}
50
51
impl<K> UnionFind<K>
52
where
53
    K: IndexType,
54
{
55
    /// Create a new `UnionFind` of `n` disjoint sets.
56
0
    pub fn new(n: usize) -> Self {
57
0
        let rank = vec![0; n];
58
0
        let parent = (0..n).map(K::new).collect::<Vec<K>>();
59
60
0
        UnionFind { parent, rank }
61
0
    }
62
63
    /// Create a new `UnionFind` with no elements.
64
0
    pub const fn new_empty() -> Self {
65
0
        Self {
66
0
            parent: Vec::new(),
67
0
            rank: Vec::new(),
68
0
        }
69
0
    }
70
71
    /// Returns the number of elements in the union-find data-structure.
72
0
    pub fn len(&self) -> usize {
73
0
        self.parent.len()
74
0
    }
75
76
    /// Returns true if there are no elements in the union-find data-structure.
77
0
    pub fn is_empty(&self) -> bool {
78
0
        self.parent.is_empty()
79
0
    }
80
81
    /// Adds a new disjoint set and returns the index of the new set.
82
    ///
83
    /// The new disjoint set is always added to the end, so the returned
84
    /// index is the same as the number of elements before calling this function.
85
    ///
86
    /// **Time Complexity**
87
    /// Takes amortized O(1) time.
88
0
    pub fn new_set(&mut self) -> K {
89
0
        let retval = K::new(self.parent.len());
90
0
        self.rank.push(0);
91
0
        self.parent.push(retval);
92
0
        retval
93
0
    }
94
95
    /// Return the representative for `x`.
96
    ///
97
    /// **Panics** if `x` is out of bounds.
98
    #[track_caller]
99
0
    pub fn find(&self, x: K) -> K {
100
0
        self.try_find(x).expect("The index is out of bounds")
101
0
    }
102
103
    /// Return the representative for `x` or `None` if `x` is out of bounds.
104
0
    pub fn try_find(&self, mut x: K) -> Option<K> {
105
0
        if x.index() >= self.len() {
106
0
            return None;
107
0
        }
108
109
        loop {
110
            // Use unchecked indexing because we can trust the internal set ids.
111
0
            let xparent = unsafe { *get_unchecked(&self.parent, x.index()) };
112
0
            if xparent == x {
113
0
                break;
114
0
            }
115
0
            x = xparent;
116
        }
117
118
0
        Some(x)
119
0
    }
120
121
    /// Return the representative for `x`.
122
    ///
123
    /// Write back the found representative, flattening the internal
124
    /// datastructure in the process and quicken future lookups.
125
    ///
126
    /// **Panics** if `x` is out of bounds.
127
    #[track_caller]
128
0
    pub fn find_mut(&mut self, x: K) -> K {
129
0
        assert!(x.index() < self.len());
130
0
        unsafe { self.find_mut_recursive(x) }
131
0
    }
132
133
    /// Return the representative for `x` or `None` if `x` is out of bounds.
134
    ///
135
    /// Write back the found representative, flattening the internal
136
    /// datastructure in the process and quicken future lookups.
137
0
    pub fn try_find_mut(&mut self, x: K) -> Option<K> {
138
0
        if x.index() >= self.len() {
139
0
            return None;
140
0
        }
141
0
        Some(unsafe { self.find_mut_recursive(x) })
142
0
    }
143
144
0
    unsafe fn find_mut_recursive(&mut self, mut x: K) -> K {
145
0
        let mut parent = *get_unchecked(&self.parent, x.index());
146
0
        while parent != x {
147
0
            let grandparent = *get_unchecked(&self.parent, parent.index());
148
0
            *get_unchecked_mut(&mut self.parent, x.index()) = grandparent;
149
0
            x = parent;
150
0
            parent = grandparent;
151
0
        }
152
0
        x
153
0
    }
154
155
    /// Returns `true` if the given elements belong to the same set, and returns
156
    /// `false` otherwise.
157
    ///
158
    /// **Panics** if `x` or `y` is out of bounds.
159
    #[track_caller]
160
0
    pub fn equiv(&self, x: K, y: K) -> bool {
161
0
        self.find(x) == self.find(y)
162
0
    }
163
164
    /// Returns `Ok(true)` if the given elements belong to the same set, and returns
165
    /// `Ok(false)` otherwise.
166
    ///
167
    /// If `x` or `y` are out of bounds, it returns `Err` with the first bad index found.
168
0
    pub fn try_equiv(&self, x: K, y: K) -> Result<bool, K> {
169
0
        let xrep = self.try_find(x).ok_or(x)?;
170
0
        let yrep = self.try_find(y).ok_or(y)?;
171
0
        Ok(xrep == yrep)
172
0
    }
173
174
    /// Unify the two sets containing `x` and `y`.
175
    ///
176
    /// Return `false` if the sets were already the same, `true` if they were unified.
177
    ///
178
    /// **Panics** if `x` or `y` is out of bounds.
179
    #[track_caller]
180
0
    pub fn union(&mut self, x: K, y: K) -> bool {
181
0
        self.try_union(x, y).unwrap()
182
0
    }
183
184
    /// Unify the two sets containing `x` and `y`.
185
    ///
186
    /// Return `Ok(false)` if the sets were already the same, `Ok(true)` if they were unified.
187
    ///
188
    /// If `x` or `y` are out of bounds, it returns `Err` with first found bad index.
189
    /// But if `x == y`, the result will be `Ok(false)` even if the indexes go out of bounds.
190
0
    pub fn try_union(&mut self, x: K, y: K) -> Result<bool, K> {
191
0
        if x == y {
192
0
            return Ok(false);
193
0
        }
194
0
        let xrep = self.try_find_mut(x).ok_or(x)?;
195
0
        let yrep = self.try_find_mut(y).ok_or(y)?;
196
197
0
        if xrep == yrep {
198
0
            return Ok(false);
199
0
        }
200
201
0
        let xrepu = xrep.index();
202
0
        let yrepu = yrep.index();
203
0
        let xrank = self.rank[xrepu];
204
0
        let yrank = self.rank[yrepu];
205
206
        // The rank corresponds roughly to the depth of the treeset, so put the
207
        // smaller set below the larger
208
0
        match xrank.cmp(&yrank) {
209
0
            Ordering::Less => self.parent[xrepu] = yrep,
210
0
            Ordering::Greater => self.parent[yrepu] = xrep,
211
0
            Ordering::Equal => {
212
0
                self.parent[yrepu] = xrep;
213
0
                self.rank[xrepu] += 1;
214
0
            }
215
        }
216
0
        Ok(true)
217
0
    }
218
219
    /// Return a vector mapping each element to its representative.
220
0
    pub fn into_labeling(mut self) -> Vec<K> {
221
        // write in the labeling of each element
222
        unsafe {
223
0
            for ix in 0..self.len() {
224
0
                let k = *get_unchecked(&self.parent, ix);
225
0
                let xrep = self.find_mut_recursive(k);
226
0
                *self.parent.get_unchecked_mut(ix) = xrep;
227
0
            }
228
        }
229
0
        self.parent
230
0
    }
231
}
232
233
impl<K> UnionFind<K> {
234
    /// Constructs a new, empty `UnionFind<K>` with at least the specified capacity.
235
    ///
236
    /// This acts similarly to [`Vec::with_capacity`].
237
0
    pub fn with_capacity(capacity: usize) -> Self {
238
0
        UnionFind {
239
0
            parent: Vec::with_capacity(capacity),
240
0
            rank: Vec::with_capacity(capacity),
241
0
        }
242
0
    }
243
244
    /// Returns the total number of elements the `UnionFind` can hold without reallocating.
245
    ///
246
    /// # Examples
247
    ///
248
    /// ```
249
    /// use petgraph::unionfind::UnionFind;
250
    ///
251
    /// let mut uf: UnionFind<u32> = UnionFind::with_capacity(10);
252
    /// uf.new_set();
253
    /// assert!(uf.capacity() >= 10);
254
    /// ```
255
    #[inline]
256
0
    pub fn capacity(&self) -> usize {
257
0
        self.parent.capacity().min(self.rank.capacity())
258
0
    }
259
260
    /// Reserves capacity for at least `additional` more elements to be inserted
261
    /// in the given `UnionFind<K>`. The collection may reserve more space to
262
    /// speculatively avoid frequent reallocations. After calling `reserve`,
263
    /// capacity will be greater than or equal to `self.len() + additional`.
264
    /// Does nothing if capacity is already sufficient.
265
    ///
266
    /// # Panics
267
    ///
268
    /// Panics if the new capacity exceeds `isize::MAX` _bytes_.
269
    ///
270
    /// # Examples
271
    ///
272
    /// ```
273
    /// use petgraph::unionfind::UnionFind;
274
    ///
275
    /// let mut uf: UnionFind<u32> = UnionFind::new(3);
276
    /// uf.reserve(10);
277
    /// assert!(uf.capacity() >= 13);
278
    /// ```
279
    #[inline]
280
0
    pub fn reserve(&mut self, additional: usize) {
281
0
        self.parent.reserve(additional);
282
0
        self.rank.reserve(additional);
283
0
    }
284
285
    /// Reserves the minimum capacity for at least `additional` more elements to
286
    /// be inserted in the given `UnionFind<K>`. Unlike [`reserve`], this will not
287
    /// deliberately over-allocate to speculatively avoid frequent allocations.
288
    /// After calling `reserve_exact`, capacity will be greater than or equal to
289
    /// `self.len() + additional`. Does nothing if the capacity is already
290
    /// sufficient.
291
    ///
292
    /// Note that the allocator may give the collection more space than it
293
    /// requests. Therefore, capacity can not be relied upon to be precisely
294
    /// minimal. Prefer [`reserve`] if future insertions are expected.
295
    ///
296
    /// [`reserve`]: UnionFind::reserve
297
    ///
298
    /// # Panics
299
    ///
300
    /// Panics if the new capacity exceeds `isize::MAX` _bytes_.
301
    ///
302
    /// # Examples
303
    ///
304
    /// ```
305
    /// use petgraph::unionfind::UnionFind;
306
    ///
307
    /// let mut uf: UnionFind<u32> =  UnionFind::new_empty();
308
    /// uf.reserve_exact(10);
309
    /// assert!(uf.capacity() >= 10);
310
    /// ```
311
    #[inline]
312
0
    pub fn reserve_exact(&mut self, additional: usize) {
313
0
        self.parent.reserve_exact(additional);
314
0
        self.rank.reserve_exact(additional);
315
0
    }
316
317
    /// Tries to reserve capacity for at least `additional` more elements to be inserted
318
    /// in the given `UnionFind<K>`. The collection may reserve more space to speculatively avoid
319
    /// frequent reallocations. After calling `try_reserve`, capacity will be
320
    /// greater than or equal to `self.len() + additional` if it returns
321
    /// `Ok(())`. Does nothing if capacity is already sufficient. This method
322
    /// preserves the contents even if an error occurs.
323
    ///
324
    /// # Errors
325
    ///
326
    /// If the capacity overflows, or the allocator reports a failure, then an error
327
    /// is returned.
328
    #[inline]
329
0
    pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> {
330
0
        self.parent
331
0
            .try_reserve(additional)
332
0
            .and_then(|_| self.rank.try_reserve(additional))
333
0
    }
334
335
    /// Tries to reserve the minimum capacity for at least `additional`
336
    /// elements to be inserted in the given `UnionFind<K>`. Unlike [`try_reserve`],
337
    /// this will not deliberately over-allocate to speculatively avoid frequent
338
    /// allocations. After calling `try_reserve_exact`, capacity will be greater
339
    /// than or equal to `self.len() + additional` if it returns `Ok(())`.
340
    /// Does nothing if the capacity is already sufficient.
341
    ///
342
    /// Note that the allocator may give the collection more space than it
343
    /// requests. Therefore, capacity can not be relied upon to be precisely
344
    /// minimal. Prefer [`try_reserve`] if future insertions are expected.
345
    ///
346
    /// [`try_reserve`]: UnionFind::try_reserve
347
    ///
348
    /// # Errors
349
    ///
350
    /// If the capacity overflows, or the allocator reports a failure, then an error
351
    /// is returned.
352
    #[inline]
353
0
    pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> {
354
0
        self.parent
355
0
            .try_reserve_exact(additional)
356
0
            .and_then(|_| self.rank.try_reserve_exact(additional))
357
0
    }
358
359
    /// Shrinks the capacity of the `UnionFind` as much as possible.
360
    ///
361
    /// The behavior of this method depends on the allocator, which may either shrink the
362
    /// collection in-place or reallocate. The resulting `UnionFind` might still have some excess capacity, just as
363
    /// is the case for [`with_capacity`]. See [`Vec::shrink_to_fit`] for more details, since the implementation is based on this method.
364
    ///
365
    /// [`with_capacity`]: UnionFind::with_capacity
366
    ///
367
    /// # Examples
368
    ///
369
    /// ```
370
    /// use petgraph::unionfind::UnionFind;
371
    ///
372
    /// let mut uf: UnionFind<u32> = UnionFind::with_capacity(10);
373
    ///
374
    /// for _ in 0..3 {
375
    ///     uf.new_set();
376
    /// }
377
    ///
378
    /// assert!(uf.capacity() >= 10);
379
    /// uf.shrink_to_fit();
380
    /// assert!(uf.capacity() >= 3);
381
    /// ```
382
    #[inline]
383
0
    pub fn shrink_to_fit(&mut self) {
384
0
        self.parent.shrink_to_fit();
385
0
        self.rank.shrink_to_fit();
386
0
    }
387
388
    /// Shrinks the capacity of the `UnionFind` with a lower bound.
389
    ///
390
    /// The capacity will remain at least as large as both the length
391
    /// and the supplied value.
392
    ///
393
    /// If the current capacity is less than the lower limit, this is a no-op.
394
    ///
395
    /// # Examples
396
    ///
397
    /// ```
398
    /// use petgraph::unionfind::UnionFind;
399
    ///
400
    /// let mut uf: UnionFind<u32> = UnionFind::with_capacity(10);
401
    ///
402
    /// for _ in 0..3 {
403
    ///     uf.new_set();
404
    /// }
405
    ///
406
    /// assert!(uf.capacity() >= 10);
407
    /// uf.shrink_to(4);
408
    /// assert!(uf.capacity() >= 4);
409
    /// uf.shrink_to(0);
410
    /// assert!(uf.capacity() >= 3);
411
    /// ```
412
    #[inline]
413
0
    pub fn shrink_to(&mut self, min_capacity: usize) {
414
0
        self.parent.shrink_to(min_capacity);
415
0
        self.rank.shrink_to(min_capacity);
416
0
    }
417
}