Satsuma
a delicious .NET graph library
 All Classes Namespaces Files Functions Variables Enumerations Enumerator Properties Pages
Bfs.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 using System.Text;
29 using System.Threading.Tasks;
30 
31 namespace Satsuma
32 {
49  public sealed class Bfs
50  {
52  public IGraph Graph { get; private set; }
53 
54  private readonly Dictionary<Node, Arc> parentArc;
55  private readonly Dictionary<Node, int> level;
56  private readonly Queue<Node> queue;
57 
58  public Bfs(IGraph graph)
59  {
60  Graph = graph;
61 
62  parentArc = new Dictionary<Node, Arc>();
63  level = new Dictionary<Node, int>();
64  queue = new Queue<Node>();
65  }
66 
69  public void AddSource(Node node)
70  {
71  if (Reached(node)) return;
72 
73  parentArc[node] = Arc.Invalid;
74  level[node] = 0;
75  queue.Enqueue(node);
76  }
77 
87  public bool Step(Func<Node, bool> isTarget, out Node reachedTargetNode)
88  {
89  reachedTargetNode = Node.Invalid;
90  if (queue.Count == 0) return false;
91 
92  Node node = queue.Dequeue();
93  int d = level[node] + 1;
94  foreach (var arc in Graph.Arcs(node, ArcFilter.Forward))
95  {
96  Node child = Graph.Other(arc, node);
97  if (parentArc.ContainsKey(child)) continue;
98 
99  queue.Enqueue(child);
100  level[child] = d;
101  parentArc[child] = arc;
102 
103  if (isTarget != null && isTarget(child))
104  {
105  reachedTargetNode = child;
106  return false;
107  }
108  }
109  return true;
110  }
111 
113  public void Run()
114  {
115  Node dummy;
116  while (Step(null, out dummy)) ;
117  }
118 
122  public Node RunUntilReached(Node target)
123  {
124  if (Reached(target)) return target; // already reached
125  Node reachedTargetNode;
126  while (Step(node => node == target, out reachedTargetNode)) ;
127  return reachedTargetNode;
128  }
129 
132  public Node RunUntilReached(Func<Node, bool> isTarget)
133  {
134  Node reachedTargetNode = ReachedNodes.FirstOrDefault(isTarget);
135  if (reachedTargetNode != Node.Invalid) return reachedTargetNode; // already reached
136  while (Step(isTarget, out reachedTargetNode)) ;
137  return reachedTargetNode;
138  }
139 
145  public bool Reached(Node x)
146  {
147  return parentArc.ContainsKey(x);
148  }
149 
152  public IEnumerable<Node> ReachedNodes { get { return parentArc.Keys; } }
153 
157  public int GetLevel(Node node)
158  {
159  int result;
160  return level.TryGetValue(node, out result) ? result : -1;
161  }
162 
165  public Arc GetParentArc(Node node)
166  {
167  Arc result;
168  return parentArc.TryGetValue(node, out result) ? result : Arc.Invalid;
169  }
170 
173  public IPath GetPath(Node node)
174  {
175  if (!Reached(node)) return null;
176 
177  var result = new Path(Graph);
178  result.Begin(node);
179  while (true)
180  {
181  Arc arc = GetParentArc(node);
182  if (arc == Arc.Invalid) break;
183  result.AddFirst(arc);
184  node = Graph.Other(arc, node);
185  }
186  return result;
187  }
188  }
189 }