我正在尝试深度优先搜索的C#实现。为了便于访问,我有Dictionary<int, List<int>>
来存储顶点和边缘。
Dict值是:
Vertex | Edges List
--------------------
0 | {1}
--------------------
1 | {2}
--------------------
2 | {0}
--------------------
static Dictionary<int, List<int>> dict = new Dictionary<int, List<int>>();
public class Graph
{
public int Vertex;
public List<int> Edges;
public Graph(int V, List<int> E)
{
Vertex = V;
Edges = E;
dict.Add(V, E);
}
public void DFS(Graph g)
{
Stack<int> stk = new Stack<int>();
int[] visited = new int[4];
stk.Push(g.Vertex);
visited[0] = g.Vertex;
int i = 1;
while (stk.Count > 0)
{
foreach (var item in dict[stk.Peek()])
{
if (!visited.Contains(item))
{
visited[i] = item;
stk.Push(item);
i++;
}
}
Console.WriteLine(stk.Peek());
stk.Pop();
}
}
我的深度优先搜索中只有0和1。我知道有不同的方法,但我相信我的方法也是方法之一,我需要帮助修复这段代码。
答案 0 :(得分:0)
据我了解,您的代码执行以下操作:
1.将第一个顶点推到堆栈
2.查看它,并搜索不在堆栈中的第一个边缘
3.将它推到堆栈上
偷看它
5.从堆栈中POP。通过此步骤,第一个Vertex(在这种情况下,它的Vertex 0)到达堆栈的顶部,然后您的代码转到2.point。
由于无法在一步中从顶点0到达顶点2,因此算法将停止。
答案 1 :(得分:0)
I'd like to suggest to you an existing, simple and useful implementation of Depth First Traversal: https://github.com/morelinq/MoreLINQ/blob/d45294865625aae1bf972f331a6737961473d136/MoreLinq/Traverse.cs#L87
The interesting part:
public static IEnumerable<T> TraverseDepthFirst<T>(T root, Func<T, IEnumerable<T>> childrenSelector)
{
if (childrenSelector == null) throw new ArgumentNullException(nameof(childrenSelector));
return _(); IEnumerable<T> _()
{
var stack = new Stack<T>();
stack.Push(root);
while (stack.Count != 0)
{
var current = stack.Pop();
yield return current;
// because a stack pops the elements out in LIFO order, we need to push them in reverse
// if we want to traverse the returned list in the same order as was returned to us
foreach (var child in childrenSelector(current).Reverse())
stack.Push(child);
}
}
}
By mirroring the implementation into your code, we'd get what follows:
public void DFS(Graph g)
{
Stack<int> stk = new Stack<int>();
HashSet<int> visited = new HashSet<int>();
stk.Push(g.Vertex);
visited.Add(g.Vertex);
while (stk.Count > 0)
{
int current = stk.Pop();
Console.WriteLine(current);
foreach (var item in dict[current])
{
if (visited.Add(item))
{
// Add returns true if the element wasn't in the set already
stk.Push(item);
}
}
}
}
I've removed i
variable as we're now using HashSet to track visited vertices, and moved Console.WriteLine
and stk.Pop()
to the beginning as that's more closely aligned with what we see in MoreLinq code, also that simplifies the code.
Your method is Depth First Search, yet you're only "visiting" all nodes (and I'm guessing that Console.WriteLine
is a placeholder for the actual "find/visit" operation). In it's current form it's Traversal operation, for Search you'd need to actually compare vertices with something you look for, and return some kind of result.