import DisjointSetItem from './DisjointSetItem'; export default class DisjointSet { /** * @param {function(value: *)} [keyCallback] */ constructor(keyCallback) { this.keyCallback = keyCallback; this.items = {}; } /** * @param {*} itemValue * @return {DisjointSet} */ makeSet(itemValue) { const disjointSetItem = new DisjointSetItem(itemValue, this.keyCallback); if (!this.items[disjointSetItem.getKey()]) { // Add new item only in case if it not presented yet. this.items[disjointSetItem.getKey()] = disjointSetItem; } return this; } /** * Find set representation node. * * @param {*} itemValue * @return {(string|null)} */ find(itemValue) { const templateDisjointItem = new DisjointSetItem(itemValue, this.keyCallback); // Try to find item itself; const requiredDisjointItem = this.items[templateDisjointItem.getKey()]; if (!requiredDisjointItem) { return null; } return requiredDisjointItem.getRoot().getKey(); } /** * Union by rank. * * @param {*} valueA * @param {*} valueB * @return {DisjointSet} */ union(valueA, valueB) { const rootKeyA = this.find(valueA); const rootKeyB = this.find(valueB); if (rootKeyA === null || rootKeyB === null) { throw new Error('One or two values are not in sets'); } if (rootKeyA === rootKeyB) { // In case if both elements are already in the same set then just return its key. return this; } const rootA = this.items[rootKeyA]; const rootB = this.items[rootKeyB]; if (rootA.getRank() < rootB.getRank()) { // If rootB's tree is bigger then make rootB to be a new root. rootB.addChild(rootA); return this; } // If rootA's tree is bigger then make rootA to be a new root. rootA.addChild(rootB); return this; } /** * @param {*} valueA * @param {*} valueB * @return {boolean} */ inSameSet(valueA, valueB) { const rootKeyA = this.find(valueA); const rootKeyB = this.find(valueB); if (rootKeyA === null || rootKeyB === null) { throw new Error('One or two values are not in sets'); } return rootKeyA === rootKeyB; } }