Satsuma
a delicious .NET graph library
 All Classes Namespaces Files Functions Variables Enumerations Enumerator Properties Pages
SpanningForest.cs
Go to the documentation of this file.
1 #region License
2 /*This file is part of Satsuma Graph Library
3 Copyright © 2013 Balázs Szalkai
4 
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8 
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12 
13  1. The origin of this software must not be misrepresented; you must not
14  claim that you wrote the original software. If you use this software
15  in a product, an acknowledgment in the product documentation would be
16  appreciated but is not required.
17 
18  2. Altered source versions must be plainly marked as such, and must not be
19  misrepresented as being the original software.
20 
21  3. This notice may not be removed or altered from any source
22  distribution.*/
23 #endregion
24 
25 using System;
26 using System.Collections.Generic;
27 using System.Linq;
28 
29 namespace Satsuma
30 {
55  public sealed class Prim<TCost>
56  where TCost : IComparable<TCost>
57  {
58  public IGraph Graph { get; private set; }
59  public Func<Arc, TCost> Cost { get; private set; }
60 
62  public HashSet<Arc> Forest { get; private set; }
64  public Subgraph ForestGraph { get; private set; }
65 
66  public Prim(IGraph graph, Func<Arc, TCost> cost)
67  {
68  Graph = graph;
69  Cost = cost;
70  Forest = new HashSet<Arc>();
71  ForestGraph = new Subgraph(graph);
72  ForestGraph.EnableAllArcs(false);
73 
74  Run();
75  }
76 
77  public Prim(IGraph graph, Dictionary<Arc, TCost> cost)
78  : this(graph, arc => cost[arc])
79  {
80  }
81 
82  private void Run()
83  {
84  Forest.Clear();
85  PriorityQueue<Node, TCost> priorityQueue = new PriorityQueue<Node, TCost>();
86  HashSet<Node> processed = new HashSet<Node>();
87  Dictionary<Node, Arc> parentArc = new Dictionary<Node, Arc>();
88 
89  // start with one point from each component
90  var components = new ConnectedComponents(Graph, ConnectedComponents.Flags.CreateComponents);
91  foreach (var c in components.Components)
92  {
93  Node root = c.First();
94  processed.Add(root);
95  foreach (var arc in Graph.Arcs(root))
96  {
97  Node v = Graph.Other(arc, root);
98  parentArc[v] = arc;
99  priorityQueue[v] = Cost(arc);
100  }
101  }
102  components = null;
103 
104  while (priorityQueue.Count != 0)
105  {
106  Node n = priorityQueue.Peek();
107  priorityQueue.Pop();
108  processed.Add(n);
109  Arc arcToAdd = parentArc[n];
110  Forest.Add(arcToAdd);
111  ForestGraph.Enable(arcToAdd, true);
112 
113  foreach (var arc in Graph.Arcs(n))
114  {
115  Node v = Graph.Other(arc, n);
116  if (processed.Contains(v)) continue;
117 
118  TCost arcCost = Cost(arc);
119  TCost vCost;
120  bool vInPriorityQueue = priorityQueue.TryGetPriority(v, out vCost);
121  if (!vInPriorityQueue || arcCost.CompareTo(vCost) < 0)
122  {
123  priorityQueue[v] = arcCost;
124  parentArc[v] = arc;
125  }
126  }
127  }
128  }
129  }
130 
152  public sealed class Kruskal<TCost>
153  where TCost : IComparable<TCost>
154  {
156  public IGraph Graph { get; private set; }
158  public Func<Arc, TCost> Cost { get; private set; }
164  public Func<Node, int> MaxDegree { get; private set; }
165 
169  public HashSet<Arc> Forest { get; private set; }
171  public Subgraph ForestGraph { get; private set; }
173  public Dictionary<Node, int> Degree { get; private set; }
174 
175  private IEnumerator<Arc> arcEnumerator; // Enumerates the arcs by cost increasing.
176  private int arcsToGo;
177  private DisjointSet<Node> components; // The components of the current spanning forest.
178 
179  public Kruskal(IGraph graph, Func<Arc, TCost> cost, Func<Node, int> maxDegree = null)
180  {
181  Graph = graph;
182  Cost = cost;
183  MaxDegree = maxDegree;
184 
185  Forest = new HashSet<Arc>();
186  ForestGraph = new Subgraph(graph);
187  ForestGraph.EnableAllArcs(false);
188  Degree = new Dictionary<Node, int>();
189  foreach (var node in Graph.Nodes()) Degree[node] = 0;
190 
191  List<Arc> arcs = Graph.Arcs().ToList();
192  arcs.Sort((a, b) => Cost(a).CompareTo(Cost(b)));
193  arcEnumerator = arcs.GetEnumerator();
194  arcsToGo = Graph.NodeCount() - new ConnectedComponents(Graph).Count;
195  components = new DisjointSet<Node>();
196  }
197 
198  public Kruskal(IGraph graph, Dictionary<Arc, TCost> cost)
199  : this(graph, arc => cost[arc], null)
200  {
201  }
202 
206  public bool Step()
207  {
208  if (arcsToGo <= 0 || arcEnumerator == null || !arcEnumerator.MoveNext())
209  {
210  arcEnumerator = null;
211  return false;
212  }
213 
214  AddArc(arcEnumerator.Current);
215  return true;
216  }
217 
219  public void Run()
220  {
221  while (Step()) ;
222  }
223 
228  public bool AddArc(Arc arc)
229  {
230  var u = Graph.U(arc);
231  if (MaxDegree != null && Degree[u] >= MaxDegree(u)) return false;
232  DisjointSetSet<Node> x = components.WhereIs(u);
233 
234  var v = Graph.V(arc);
235  if (MaxDegree != null && Degree[v] >= MaxDegree(v)) return false;
236  DisjointSetSet<Node> y = components.WhereIs(v);
237 
238  if (x == y) return false; // cycle
239 
240  Forest.Add(arc);
241  ForestGraph.Enable(arc, true);
242  components.Union(x, y);
243  Degree[u]++;
244  Degree[v]++;
245  arcsToGo--;
246  return true;
247  }
248  }
249 }