quick-union-union-find
Version:
Quick Union Union Find using ES next
150 lines (140 loc) • 4.9 kB
JavaScript
/**
* 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;