mirror of
https://github.com/gonum/gonum.git
synced 2025-10-06 07:37:03 +08:00
88 lines
2.4 KiB
Go
88 lines
2.4 KiB
Go
// 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++
|
|
}
|
|
}
|