Last active
November 19, 2022 16:58
-
-
Save SamChristy/2da9e1da30e24a6f667af3de2e1bf44a to your computer and use it in GitHub Desktop.
An efficient Disjoint Set implementation (using compressed trees and dense storage).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * (If a number is used, it must be > -1!) | |
| */ | |
| type DSNode = number | string; | |
| class DisjointSet { | |
| protected readonly parents: Map<DSNode, DSNode | number> = new Map(); | |
| protected count = 0; | |
| protected findRoot(node: DSNode): DSNode { | |
| const parent = this.parents.get(node) ?? -1; | |
| // If parent's value is < 0, it's actually the rank value | |
| // of the node (which is the root of its tree). | |
| if (parent < 0) return node; | |
| const root = this.findRoot(parent); // <--- Tree compression ❤️ | |
| this.parents.set(node, root); | |
| return root; | |
| } | |
| public add(node: DSNode): void { | |
| if (this.parents.get(node) !== undefined) return; | |
| this.parents.set(node, -1); | |
| this.count++; | |
| } | |
| // Values must be >= 0! | |
| public union(a: DSNode, b: DSNode): void { | |
| // We need to add the nodes if we haven't already... | |
| this.add(a); | |
| this.add(b); | |
| const aRoot = this.findRoot(a); | |
| const bRoot = this.findRoot(b); | |
| // If roots are equal, they're already in the same tree and | |
| // there's nothing we need to do. | |
| if (aRoot === bRoot) return; | |
| const aRank = this.parents.get(aRoot) as number; | |
| const bRank = this.parents.get(bRoot) as number; | |
| // (Rank ordering is reversed, as we use negative numbers to | |
| // differentiate from node names.) | |
| if (aRank < bRank) { | |
| // Attach A to B and update its rank, to include B's | |
| // previous rank. | |
| this.parents.set(aRoot, aRank + bRank); | |
| this.parents.set(bRoot, aRoot); | |
| this.count--; | |
| } else { | |
| this.parents.set(bRoot, aRank + bRank); | |
| this.parents.set(aRoot, bRoot); | |
| this.count--; | |
| } | |
| } | |
| public getCount(): number { | |
| return this.count; | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment