blob: bab7fc6f77e545a443a1c3ef702429b3f37b2bb2 [file] [log] [blame]
// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
/// Implementation of a union-find algorithm.
///
/// See https://en.wikipedia.org/wiki/Disjoint-set_data_structure
import 'dart:collection';
class UnionFindNode<T> {
final T value;
UnionFindNode<T>? parent;
UnionFindNode(this.value);
}
class UnionFind<T> {
final bool _useIdentity;
final Map<T, UnionFindNode<T>> _nodeMap;
UnionFind({bool useIdentity: false})
: _nodeMap = useIdentity ? new LinkedHashMap.identity() : {},
_useIdentity = useIdentity;
UnionFind<T> clone() {
UnionFind<T> newUnionFind = new UnionFind<T>(useIdentity: _useIdentity);
Map<UnionFindNode<T>, UnionFindNode<T>> oldToNewMap = {};
UnionFindNode<T> getNewNode(UnionFindNode<T> oldNode) {
UnionFindNode<T> newNode = newUnionFind[oldNode.value];
return oldToNewMap[oldNode] = newNode;
}
for (UnionFindNode<T> oldNode in _nodeMap.values) {
UnionFindNode<T> newNode = getNewNode(oldNode);
if (oldNode.parent != null) {
newNode.parent = getNewNode(oldNode.parent!);
}
}
return newUnionFind;
}
UnionFindNode<T> operator [](T value) =>
_nodeMap[value] ??= new UnionFindNode<T>(value);
Iterable<UnionFindNode<T>> get nodes => _nodeMap.values;
Iterable<T> get values => nodes.map((n) => n.value);
UnionFindNode<T> findNode(UnionFindNode<T> node) {
if (node.parent != null) {
// Perform path compression by updating to the effective target.
return node.parent = findNode(node.parent!);
}
return node;
}
void unionOfValues(T a, T b) {
unionOfNodes(this[a], this[b]);
}
UnionFindNode<T> unionOfNodes(UnionFindNode<T> a, UnionFindNode<T> b) {
UnionFindNode<T> rootA = findNode(a);
UnionFindNode<T> rootB = findNode(b);
if (rootA != rootB) {
return rootB.parent = rootA;
}
return rootA;
}
bool valuesInSameSet(T a, T b) {
UnionFindNode<T>? node1 = _nodeMap[a];
UnionFindNode<T>? node2 = _nodeMap[b];
return node1 != null && node2 != null && nodesInSameSet(node1, node2);
}
bool nodesInSameSet(UnionFindNode<T> a, UnionFindNode<T> b) {
return findNode(a) == findNode(b);
}
}