【发布时间】:2013-10-06 20:47:42
【问题描述】:
假设我有下图(箭头表示连接方向),我想计算黑色节点簇的大小:
在内存中组织为节点列表,这样每个节点都有一个其邻居节点的列表。我想从任何节点开始计算有多少节点有node[i].State == 1,如果给定节点也处于状态1。因此,我实现了一个方法Node.GetClusterSize(),在其中我计算集群大小(它基于在深度优先搜索算法中):
public class Node
{
public Int32 State { get; private set; } // 0 = white; 1 = black;
public Boolean Visited { get; private set; }
public List<Node> InputNeigh { get; private set; } // list of references to
// neighbors nodes
public Int32 GetClusterSize()
{
this.Visited = true;
if (this.State == 1)
{
Int32 s = 1, i = 0;
while (i < this.InputNeigh.Count)
{
if (!this.InputNeigh[i].Visited)
{
s += this.InputNeigh[i].GetClusterSize();
}
i++;
}
this.Visited = false; // this is an important step, I'll explain why
return s;
}
else
{
return 0;
}
}
public void Evolve() { /* doesn't matter for this question */ }
}
现在,我需要将节点标记为未访问,因为我在主模拟的每个时间步计算每个节点的集群大小(节点的状态会随着时间而变化,因此集群可能会在下一个时间步改变大小)。
如果我有一个外部布尔列表,而不是 Node 对象中的标志,则可以轻松解决此问题,给定元素 i 对应于节点 i:List<Boolean> nodeStatus,并通过此列表作为对函数 Node.GetClusterSize() 的引用。但是,我将不得不在每个时间步重置此列表,从而减慢代码速度(性能很重要!)。
上述代码的失败正是在遍历其邻居后将该节点标记为未访问。使用以下树可以更好地可视化这种情况(从左到右并假设我首先调用node[0].GetClusterSize()):
深度优先搜索遍历上面树中的蓝色路径,当它到达节点3时,它知道它的所有邻居都已被访问,将3标记为未访问并返回@987654334 @。由于3 是2 的下一个要访问的邻居,并且3 被标记为未访问(尽管它已经被访问过),所以它再次检查并且算法进入StackOverflow 异常,或者,在最好,返回错误的集群大小。
因此,我想出了两个想法,虽然我仍然不知道如何实现它们:
1) 实现广度优先搜索算法;虽然我不知道如何将这个概念应用到所呈现的情况。
2) 以顺序方式(非递归)实现深度优先搜索。然而,我无法想象这是怎么可能的。
您有什么想法可以解决这个问题吗?有什么建议吗?
提前感谢您!
PS:图表可能比这个例子大,并且在网络中可能有多个黑色集群在同一时间,彼此断开。因此,不仅仅是计算黑色元素的问题。
【问题讨论】:
标签: c# algorithm graph simulation