blob: 4f530f69d12c692877e65c98c357a8cbd944ec8d [file] [log] [blame]
// Copyright ©2014 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package path
// A disjoint set is a collection of non-overlapping sets. That is, for any two sets in the
// disjoint set, their intersection is the empty set.
//
// A disjoint set has three principle operations: Make Set, Find, and Union.
//
// Make set creates a new set for an element (presuming it does not already exist in any set in
// the disjoint set), Find finds the set containing that element (if any), and Union merges two
// sets in the disjoint set. In general, algorithms operating on disjoint sets are "union-find"
// algorithms, where two sets are found with Find, and then joined with Union.
//
// A concrete example of a union-find algorithm can be found as discrete.Kruskal -- which unions
// two sets when an edge is created between two vertices, and refuses to make an edge between two
// vertices if they're part of the same set.
type disjointSet struct {
master map[int64]*disjointSetNode
}
type disjointSetNode struct {
parent *disjointSetNode
rank int
}
func newDisjointSet() *disjointSet {
return &disjointSet{master: make(map[int64]*disjointSetNode)}
}
// If the element isn't already somewhere in there, adds it to the master set and its own tiny set.
func (ds *disjointSet) makeSet(e int64) {
if _, ok := ds.master[e]; ok {
return
}
dsNode := &disjointSetNode{rank: 0}
dsNode.parent = dsNode
ds.master[e] = dsNode
}
// Returns the set the element belongs to, or nil if none.
func (ds *disjointSet) find(e int64) *disjointSetNode {
dsNode, ok := ds.master[e]
if !ok {
return nil
}
return find(dsNode)
}
func find(dsNode *disjointSetNode) *disjointSetNode {
if dsNode.parent != dsNode {
dsNode.parent = find(dsNode.parent)
}
return dsNode.parent
}
// Unions two subsets within the disjointSet.
//
// If x or y are not in this disjoint set, the behavior is undefined. If either pointer is nil,
// this function will panic.
func (ds *disjointSet) union(x, y *disjointSetNode) {
if x == nil || y == nil {
panic("Disjoint Set union on nil sets")
}
xRoot := find(x)
yRoot := find(y)
if xRoot == nil || yRoot == nil {
return
}
if xRoot == yRoot {
return
}
if xRoot.rank < yRoot.rank {
xRoot.parent = yRoot
} else if yRoot.rank < xRoot.rank {
yRoot.parent = xRoot
} else {
yRoot.parent = xRoot
xRoot.rank++
}
}