gdsu is a modern, type-safe, composable Disjoint Set Union (DSU) / Union-Find Go library.
It provides a clean DSU interface with two interchangeable implementations:
- Sparse DSU — generic, map-backed, supports any comparable type, grows dynamically
- Compact DSU — high-performance integer-indexed version using slices, fixed capacity
This library is designed for algorithmic workloads, data pipelines, graph theory, clustering, and any use-case involving connectivity queries.
Located in: gdsu.go
type DSU[T comparable] interface {
Find(x T) T // Find returns the representative element (root) of x
Union(x, y T) bool // Union merges the sets containing x and y
Connected(x, y T) bool // Connected reports whether x and y are in the same set
IsMember(x T) bool // IsMember reports whether x is present (no mutation)
Groups() map[T][]T // Groups returns all connected components
}Both implementations — sparse and compact — satisfy this interface.
Located in: sparse/sparse.go
- Works with any comparable type: strings, integers, structs, user-defined keys
- Supports dynamic growth — no fixed initial capacity
- Backed by Go maps (
map[T]T) - Ideal for:
- Arbitrary keys
- Sparse connectivity
- Unpredictable element ranges
- Rapid prototyping with rich data types
package main
import (
"fmt"
"github.com/arunksaha/gdsu/sparse"
)
func main() {
dsu := sparse.New[string]()
dsu.Union("apple", "banana")
dsu.Union("banana", "cherry")
fmt.Println(dsu.Connected("apple", "cherry")) // true
fmt.Println(len(dsu.Groups())) // 1
}Located in: compact/compact.go
- Very fast, minimal overhead
- Uses contiguous slices for parent and rank
- Requires fixed capacity at initialization (
New(size)) - Ideal for:
- Graph algorithms
- Tight inner loops
- Integer node IDs (
0..N-1) - Performance-critical workloads
package main
import (
"fmt"
"github.com/arunksaha/gdsu/compact"
)
func main() {
dsu := compact.New(10) // supports 0..9
dsu.Union(1, 2)
dsu.Union(2, 3)
fmt.Println(dsu.Connected(1, 3)) // true
fmt.Println(dsu.Groups())
}Benchmark files:
sparse/sparse_benchmark_test.gocompact/compact_benchmark_test.gocomparison/comparison_benchmark_test.go
Benchmarks include:
- Union performance
- Find performance
- Connected queries
- Mixed-operation simulations
- Sparse vs compact comparison
- Memory profiling
Compact is optimized for pure speed; sparse is optimized for flexibility.
.
├── compact
│ ├── compact_benchmark_test.go
│ ├── compact_example_test.go
│ ├── compact.go
│ └── compact_test.go
├── comparison
│ └── comparison_benchmark_test.go
├── gdsu.go
├── gdsu_test.go
├── go.mod
├── LICENSE
├── Makefile
├── README.md
└── sparse
├── sparse_benchmark_test.go
├── sparse_example_test.go
├── sparse.go
└── sparse_test.go
Often (Go) DSU implementations:
- Work only with
int - Require fixed capacity specified at construction
- Do not support generic types
- Do not provide an interface abstraction
gdsu improves on all of these:
Both implementations satisfy the same DSU[T] interface.
Supports any comparable type, grows dynamically.
Optimized for numeric workloads.
go get github.com/arunksaha/gdsuChoose sparse or compact depending on your needs.
Example usage is provided in each subpackage’s *_example_test.go.
The Makefile provides several convenience targets, namely:
-
lintto run various formatting and static analysis tools, e.g.,fmt,vet,staticcheck,tidy -
testto run unit tests -
coverageto test coverage -
covhtmlto view test coverage results in pretty color-coded html -
docto generate documentation for local viewing -
benchmarkto run all the benchmark tests
Issues and PRs are welcome!