你的方法,以及加里的答案,都是完全合理的方法,可以重新界定对物体进行复读的抽象概念。 然而,我看到四个潜在的问题。 也许不是了解你的准确情况,或许是你们的不问问题,或者也许你们应当考虑:
首先,用你正在读写的图表走得太长。 您暗中做了“深度第一<>>->查询,即便在支持尾声再造的建筑中,你的方法也不可能轻易地加以重复,因此,你冒着摆脱警钟的风险。
第二,你假定图表是杂质;如果图表是空洞的,你肯定会离开 st空间。
Third, I don t see why the traversal algorithm returns an entity. Why isn t this method void? Or, if you are using the return as an accumulator to accumulate the value computed by the traversal, then why does the recursive step not do something with the entity returned?
第四,你在此似乎有点关切。 打电话者负责确定(1) 图表的根源是什么,(2) 每一节点应做什么。 但是,被点击者负责(3)把哪些物体重新拿到。 这对我来说似乎很奇怪。 打电话者正在提供起点;打电话者在如何继续工作方面是否有发言权?
我通常解决这个问题如下:
- Use an explicit stack allocated on the heap rather than using the call stack for control flow
- Track nodes I ve visited before and do not re-visit them
- Have the caller determine when an object has traversable children. If the caller wishes the traversal to "bottom out" in the base case then the caller can return an empty set of children.
如果我想要一个蓄谋者的话,我就可执行像这一简图:
static R DepthFirstGraphAccumulate<T, R>(
T root,
Func<T, IEnumerable<T>> children,
Func<T, R, R> accumulate)
{
var accumulator = default(R);
var visited = new HashSet<T>();
var stack = new Stack<T>;
stack.Push(root);
while(stack.Count != 0)
{
var current = stack.Pop();
if (!visited.Contains(current))
{
visited.Add(current);
foreach(var child in children(current))
stack.Push(child);
accumulator = accumulate(current, accumulator);
}
}
return accumulator;
}
因此,例如,如果我有一幅愤怒的图表,我想总结一下从某个起的节点可以达到的节点,我就说:
int total = DepthFirstGraphAccumulate<Node, int>(
startNode,
node=>node.NeighbouringNodes,
(node, sum)=>node.Value + sum);
然而,我被诱惑,在“让我们分开关注”的道路上走了一步,说,犹豫不决,只字不提:
static IEnumerable<T> DepthFirstGraphTraversal<T>(
T root,
Func<T, IEnumerable<T>> children)
{
var visited = new HashSet<T>();
var stack = new Stack<T>;
stack.Push(root);
while(stack.Count != 0)
{
var current = stack.Pop();
if (!visited.Contains(current))
{
visited.Add(current);
foreach(var child in children(current))
stack.Push(child);
yield return current;
}
}
}
现在,如果我想对图表中的每一个节点采取一些行动,我只说:
foreach(var node in DepthFirstGraphTraversal<Node>(startNode, n=>n.NeighbouringNodes))
DoSomething(node);
如果我想表达“每一条与某种条件相对应的东西”的概念,那么我就写了:
var nodes = from node in DepthFirstGraphTraversal<Node>(startNode, n=>n.NeighbouringNodes)
where condition(node)
select node;
foreach(var matchingNode in nodes) DoSomething(matchingNode);