mst

package
v0.0.0-...-e471070 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 25, 2021 License: GPL-3.0 Imports: 2 Imported by: 0

Documentation

Overview

Package mst computes minimum spanning tree for undirected edge-weighted graph. Weight represents a cost (or time) that it takes to propagate through the edge (airline map where weights are distances or fares). Minimizing the cost is naturally of interest in such situations.

A spanning tree of a graph is a connected subgraph with no cycles that includes all the vertices. A min spanning tree (MST) of a graph is a spanning tree whose weights (sum) is no larger than weight of any other spanning tree.

A cut of a graph is a partition of its vertices into two nonempty disjoint sets. A crossing edge of a cut is an edge that connects a vertex in one set with a vertex in the other. Min-weight crossing edge must be in the MST.

The cut property is the basis for Prim's and Kruskal's algorithms for the MST problem. They are special cases of a general paradigm known as greedy algorithm: apply the cut property to accept an edge as an MST edge, continuing until finding all of the MST edges.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type AdjacencyList

type AdjacencyList struct {
	// contains filtered or unexported fields
}

AdjacencyList maintains a vertex-indexed array of adjacency lists of edges.

func NewAdjacencyList

func NewAdjacencyList(vertices int) *AdjacencyList

NewAdjacencyList creates a graph represented as an array of adjacency lists.

func (*AdjacencyList) Add

func (g *AdjacencyList) Add(e *Edge)

Add adds a new edge connecting v and w vertices.

func (*AdjacencyList) Adjacent

func (g *AdjacencyList) Adjacent(v int) []*Edge

Adjacent returns edges incident to vertex v.

func (*AdjacencyList) EdgeCount

func (g *AdjacencyList) EdgeCount() int

EdgeCount returns number of edges in the graph.

func (*AdjacencyList) Edges

func (g *AdjacencyList) Edges() []*Edge

Edges returns all edges in this graph.

func (*AdjacencyList) VertexCount

func (g *AdjacencyList) VertexCount() int

VertexCount returns number of vertices in the graph.

type Edge

type Edge struct {
	V      int
	W      int
	Weight float32
}

Edge represents graph's edge.

func (*Edge) Either

func (e *Edge) Either() int

Either returns either of this edge's vertices. This is useful when neither vertex is known, a client can use the idiomatic code v, w = e.Either(), e.Other(v) to access an edge's two vertices.

func (*Edge) Other

func (e *Edge) Other(v int) int

Other helps to fund the other vertex when it knows v. It returns -1 if v doesn't belong to the edge.

func (*Edge) String

func (e *Edge) String() string

type Kruskal

type Kruskal struct {
	// contains filtered or unexported fields
}

Kruskal is an implementation of Kruskal's algorithm which uses priority queue to hold edges not yet examined, and a union-find data structure for identifying ineligible edges.

func NewKruskal

func NewKruskal(g *AdjacencyList) *Kruskal

NewKruskal processes the edges in order of their weight (smallest to largest), taking for the MST each edge that doesn't form a cycle with edges previously added, stopping after adding V-1 edges. The edges form a forest of trees that evolves gradually into a single tree, the MST.

Kruskal's algorithm uses space proportional to E and time proportional to E * log E in the worst case. The cost bound is conservative, since the algorithm terminates after finding V-1 MST edges. Kruskal's algorithm is generally slower than Prim's because it has to do a connected operation for each edge.

Example
g := NewAdjacencyList(8)
g.Add(&Edge{V: 4, W: 5, Weight: 0.35})
g.Add(&Edge{V: 4, W: 7, Weight: 0.37})
g.Add(&Edge{V: 5, W: 7, Weight: 0.28})
g.Add(&Edge{V: 0, W: 7, Weight: 0.16})
g.Add(&Edge{V: 1, W: 5, Weight: 0.32})
g.Add(&Edge{V: 0, W: 4, Weight: 0.38})
g.Add(&Edge{V: 2, W: 3, Weight: 0.17})
g.Add(&Edge{V: 1, W: 7, Weight: 0.19})
g.Add(&Edge{V: 0, W: 2, Weight: 0.26})
g.Add(&Edge{V: 1, W: 2, Weight: 0.36})
g.Add(&Edge{V: 1, W: 3, Weight: 0.29})
g.Add(&Edge{V: 2, W: 7, Weight: 0.34})
g.Add(&Edge{V: 6, W: 2, Weight: 0.40})
g.Add(&Edge{V: 3, W: 6, Weight: 0.52})
g.Add(&Edge{V: 6, W: 0, Weight: 0.58})
g.Add(&Edge{V: 6, W: 4, Weight: 0.93})

mst := NewKruskal(g)
for _, e := range mst.Edges() {
	fmt.Println(e)
}
fmt.Printf("%.5f", mst.Weight())
Output:

0-7 0.16000
2-3 0.17000
1-7 0.19000
0-2 0.26000
5-7 0.28000
4-5 0.35000
6-2 0.40000
1.81000

func (*Kruskal) Edges

func (k *Kruskal) Edges() []*Edge

Edges returns all of the MST edges in increasing order of their weights.

func (*Kruskal) Weight

func (k *Kruskal) Weight() float32

Weight calculates weight of MST. It requires iterating through the tree edges to add up the edge weights (lazy approach). In eager approach a running total would be kept.

type LazyPrim

type LazyPrim struct {
	// contains filtered or unexported fields
}

LazyPrim is a lazy version of Prim's algorithm to compute MST. It uses space proportional to E (number of edges) and time proportional to E * log E in the worst case. The bottleneck is the number of edge-weighted comparisons in the priority queue methods insert and delete min. In practice, the upper bound on the running time is a bit conservative because the number of edges on the priority queue is typically much less than E.

func NewLazyPrim

func NewLazyPrim(g *AdjacencyList) *LazyPrim

NewLazyPrim computes MST using Prim's algorithm: take an edge from the priority queue and (if it is eligible) add it to the tree, and also add to the tree the new vertex that it leads to, updating the set of crossing edges by calling visit with that vertex as argument.

This implementation is a lazy approach where ineligible edges are left in the priority queue.

Example
g := NewAdjacencyList(8)
g.Add(&Edge{V: 4, W: 5, Weight: 0.35})
g.Add(&Edge{V: 4, W: 7, Weight: 0.37})
g.Add(&Edge{V: 5, W: 7, Weight: 0.28})
g.Add(&Edge{V: 0, W: 7, Weight: 0.16})
g.Add(&Edge{V: 1, W: 5, Weight: 0.32})
g.Add(&Edge{V: 0, W: 4, Weight: 0.38})
g.Add(&Edge{V: 2, W: 3, Weight: 0.17})
g.Add(&Edge{V: 1, W: 7, Weight: 0.19})
g.Add(&Edge{V: 0, W: 2, Weight: 0.26})
g.Add(&Edge{V: 1, W: 2, Weight: 0.36})
g.Add(&Edge{V: 1, W: 3, Weight: 0.29})
g.Add(&Edge{V: 2, W: 7, Weight: 0.34})
g.Add(&Edge{V: 6, W: 2, Weight: 0.40})
g.Add(&Edge{V: 3, W: 6, Weight: 0.52})
g.Add(&Edge{V: 6, W: 0, Weight: 0.58})
g.Add(&Edge{V: 6, W: 4, Weight: 0.93})

mst := NewLazyPrim(g)
for _, e := range mst.Edges() {
	fmt.Println(e)
}
fmt.Printf("%.5f", mst.Weight())
Output:

0-7 0.16000
1-7 0.19000
0-2 0.26000
2-3 0.17000
5-7 0.28000
4-5 0.35000
6-2 0.40000
1.81000

func (*LazyPrim) Edges

func (lp *LazyPrim) Edges() []*Edge

Edges returns all of the MST edges.

func (*LazyPrim) Weight

func (lp *LazyPrim) Weight() float32

Weight calculates weight of MST. It requires iterating through the tree edges to add up the edge weights (lazy approach). In eager approach a running total would be kept.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL