UNPKG

quick-union-union-find

Version:

Quick Union Union Find using ES next

150 lines (140 loc) 4.9 kB
/** * This code is based on http://algs4.cs.princeton.edu/15uf/QuickUnionUF.java.html * The `QuickUnionUF` class represents a `union–find data type` * (also known as the `disjoint-sets data type`). * It supports the `union` and `find` operations, * along with a `connected` operation for determining whether * two sites are in the same component and a `count` operation that * returns the total number of components. * * The union–find data type models connectivity among a set of `n` * sites, named 0 through `n`–1. * The `is-connected-to` relation must be an * `equivalence relation`: * * - `Reflexive`: `p` is connected to `p`. * - `Symmetric`: If `p` is connected to `q`, * then `q` is connected to `p`. * - `Transitive`: If `p` is connected to `q` * and `q` is connected to `r`, then * `p` is connected to `r`. * * * An equivalence relation partitions the sites into * `equivalence classes` (or `components`). In this case, * two sites are in the same component if and only if they are connected. * Both sites and components are identified with integers between 0 and * `n`–1. * Initially, there are `n` components, with each site in its * own component. The `component identifier` of a component * (also known as the `root`, `canonical element`, `leader`, * or `set representative`) is one of the sites in the component: * two sites have the same component identifier if and only if they are * in the same component. * * -`union`(`p`, `q`) adds a * connection between the two sites `p` and `q`. * If `p` and `q` are in different components, * then it replaces * these two components with a new component that is the union of * the two. * -`find`(`p`) returns the component * identifier of the component containing `p`. * -`connected`(`p`, `q`) * returns true if both `p` and `q` * are in the same component, and false otherwise. * -`count`() returns the number of components. * * * The component identifier of a component can change * only when the component itself changes during a call to * `union`—it cannot change during a call * to `find`, `connected`, or `count`. * * This implementation uses quick union. * Initializing a data structure with `n` sites takes linear time. * Afterwards, the `union`, `find`, and `connected` * operations take linear time (in the worst case) and the * `count` operation takes constant time. * * * For additional documentation, see <a href="http://algs4.cs.princeton.edu/15uf">Section 1.5</a> of * *Algorithms, 4th Edition* by Robert Sedgewick and Kevin Wayne. */ 'use strict'; class QuickUnionUF { /** * Initializes an empty union–find data structure with `n` sites * `0 through `n-1`. Each site is initially in its own * component. * * @param n the number of sites * @throws RangeError: Invalid array length if `n < 0` */ constructor(n) { this._count = n; // number of components this._parent = new Array(n); // parent[i] = parent of i for (let i = 0; i < n; i++) { this._parent[i] = i; } } /** * Returns the number of components. * * @return the number of components (between `1` and `n`) */ get count() { return this._count; } /** * Returns the component identifier for the component containing site `p`. * * @param p the integer representing one site * @return the component identifier for the component containing site `p` * @throws Index Out Of Bounds Exception unless `0 <= p < n` */ find(p) { this.validate(p); while (p !== this._parent[p]) { p = this._parent[p]; } return p; } /** validate that p is a valid index * @throws Index Out Of Bounds Exception unless `0 <= p < n` */ validate(p) { let n = this._parent.length; if (p < 0 || p >= n) { throw `Index Out Of Bounds. (index ${p} is not between 0 and ${n-1})`; } } /** * Returns true if the the two sites are in the same component. * * @param p the integer representing one site * @param q the integer representing the other site * @return `true` if the two sites `p` and `q` are in the same component; * `false` otherwise * @throws Index Out Of Bounds Exception unless `0 <= p < n` */ connected(p, q) { return this.find(p) === this.find(q); } /** * Merges the component containing site `p` with the * the component containing site `q`. * * @param p the integer representing one site * @param q the integer representing the other site * @throws Index Out Of Bounds Exception unless `0 <= p < n` */ union(p, q) { let rootP = this.find(p); let rootQ = this.find(q); if (rootP === rootQ) return; this._parent[rootP] = rootQ; this._count--; } } module.exports = QuickUnionUF;