79 lines
2.6 KiB
Dart
79 lines
2.6 KiB
Dart
|
// Copyright (c) 2012, scribeGriff (Richard Griffith)
|
||
|
// https://github.com/scribeGriff/graphlab
|
||
|
// All rights reserved. Please see the LICENSE.md file.
|
||
|
//
|
||
|
// Converted to modern Dart by Pyrex Panjakar.
|
||
|
|
||
|
/// A disjoint sets ADT implemented with a Union-Find data structure.
|
||
|
///
|
||
|
/// Performs union-by-rank and path compression. Elements are represented
|
||
|
/// by ints, numbered from zero.
|
||
|
///
|
||
|
/// Each disjoint set has one element designated as its root.
|
||
|
/// Negative values indicate the element is the root of a set. The absolute
|
||
|
/// value of a negative value is the number of elements in the set.
|
||
|
/// Positive values are an index to where the root was last known to be.
|
||
|
/// If the set has been unioned with another, the last known root will point
|
||
|
/// to a more recent root.
|
||
|
///
|
||
|
/// var a = new UnionFind(myGraph.length);
|
||
|
///
|
||
|
/// var u = a.find(myGraph[i][0]);
|
||
|
/// var v = a.find(myGraph[i][1]);
|
||
|
/// a.union(u, v);
|
||
|
///
|
||
|
/// Reference: Direct port of Mark Allen Weiss' UnionFind.java
|
||
|
class UnionFind {
|
||
|
late final List<int> array;
|
||
|
|
||
|
/// Construct a disjoint sets object.
|
||
|
///
|
||
|
/// numElements is the initial number of elements--also the initial
|
||
|
/// number of disjoint sets, since every element is initially in its
|
||
|
/// own set.
|
||
|
UnionFind(int numElements) {
|
||
|
// The array is zero based but the vertices are 1 based,
|
||
|
// so we extend the array by 1 element to account for this.
|
||
|
array = [for (var i = 0; i < numElements; i++) -1];
|
||
|
}
|
||
|
|
||
|
/// union() unites two disjoint sets into a single set. A union-by-rank
|
||
|
/// heuristic is used to choose the new root.
|
||
|
///
|
||
|
/// a is an element in the first set.
|
||
|
/// b is an element in the first set.
|
||
|
void union(int a, int b) {
|
||
|
int rootA = find(a);
|
||
|
int rootB = find(b);
|
||
|
|
||
|
if (rootA == rootB) return;
|
||
|
|
||
|
if (array[rootB] < array[rootA]) {
|
||
|
// root_b has more elements, so leave it as the root.
|
||
|
// first, indicate that the set represented by root_b has grown.
|
||
|
array[rootB] += array[rootA];
|
||
|
// Then, point the root of set a at set b.
|
||
|
array[rootA] = rootB;
|
||
|
} else {
|
||
|
array[rootA] += array[rootB];
|
||
|
array[rootB] = rootA;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// find() finds the (int) name of the set containing a given element.
|
||
|
/// Performs path compression along the way.
|
||
|
///
|
||
|
/// x is the element sought.
|
||
|
/// returns the set containing x.
|
||
|
int find(int x) {
|
||
|
if (array[x] < 0) {
|
||
|
return x; // x is the root of the tree; return it
|
||
|
} else {
|
||
|
// Find out who the root is; compress path by making the root
|
||
|
// x's parent.
|
||
|
array[x] = find(array[x]);
|
||
|
return array[x]; // Return the root
|
||
|
}
|
||
|
}
|
||
|
}
|