- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
假设我有下图(箭头表示连接方向),我想计算黑色节点簇的大小:
它在内存中被组织为一个节点列表,这样每个节点都有一个它的邻居节点列表。我想数一数,从任何节点开始,有多少节点有 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
中没有标志,这个问题可以很容易地解决。对象,我有一个 bool 值的外部列表,它是给定元素 i
对应节点i
: List<Boolean> nodeStatus
,并将此列表作为对函数 Node.GetClusterSize()
的引用传递.但是,我将不得不在每个时间步重置此列表,从而减慢代码速度(性能很重要!)。
上述代码的失败正是在遍历其邻居后将该节点标记为未访问过。使用以下树可以更好地形象化这种情况(从左到右访问并假设我首先调用 node[0].GetClusterSize()
):
深度优先搜索遍历上面树中的蓝色路径,当它到达节点 3
时,它知道它的所有邻居都已经被访问过,标记为3
未访问并返回 s = 1
.作为3
是2
的下一个邻居被访问,并且3
被标记为未访问过(尽管它已经被访问过),它再次检查并且算法进入 StackOverflow
异常,或者充其量返回错误的集群大小。
因此,我想到了两个想法,虽然我仍然不知道如何实现它们:
1) 实现广度优先搜索算法;虽然我不知道如何将这个概念应用到目前的情况。
2) 以顺序方式(非递归方式)实现深度优先搜索。尽管如此,我无法想象这怎么可能。
你有什么想法可以解决这个问题吗?有什么建议吗?
PS:图可以远大于这个例子,网络中可能有多个黑色簇 < strong>同时,彼此断开连接。因此,不仅仅是计算黑色元素的问题。
最佳答案
不要改变你试图查询的对象;那种方式是疯狂的,因为正如你所注意到的,你必须取消改变对象。
这样看。您定义了一个关系。如果黑色节点之间直接存在任何边,则黑色节点与另一个黑色节点相关。当给定一个黑色节点时,您希望计算此关系的自反和传递闭包 的大小。
在您的示例中,关系似乎也是对称的,因此闭包将定义一个等价类,然后您的问题是“给定一个成员,找出其等价类的大小。
那么让我们解决更一般的问题。
什么是关系?正如评论者指出的那样,关系实际上是一组有序对。但是将您的关系视为一个函数很方便,当给定一个元素时,它会为您提供与其相关的所有元素的序列。在这种情况下:给定一个黑色节点,关系函数会为您提供所有相邻黑色节点的序列。
这里我们有一个非递归方法,当给定一个项目和一个关系时,它会计算该关系的传递闭包:
static HashSet<T> TransitiveClosure<T>(
Func<T, IEnumerable<T>> relation,
T item)
{
var closure = new HashSet<T>();
var stack = new Stack<T>();
stack.Push(item);
while(stack.Count > 0)
{
T current = stack.Pop();
foreach(T newItem in relation(current))
{
if (!closure.Contains(newItem))
{
closure.Add(newItem);
stack.Push(newItem);
}
}
}
return closure;
}
请注意,这是一个带循环检测的非递归深度优先遍历。
练习:您可以对此实现做哪些简单的更改,以将其转变为带循环检测的非递归广度优先遍历?
我们很容易创建自反和传递闭包:
static HashSet<T> TransitiveAndReflexiveClosure<T>(
Func<T, IEnumerable<T>> relation,
T item)
{
var closure = TransitiveClosure(relation, item);
closure.Add(item);
return closure;
}
练习:你的关系是对称的,这意味着当我们从一个节点 X 开始并访问一个邻居 Y,然后当我们处理 Y 时它会将 X 放回堆栈,最终在关闭。因此没有必要采取自反闭包。
前面的说法不正确; 是需要采取自反闭包。该论证中的哪个句子包含第一个错误?
现在你有了一个可以很容易调用的方法:
var cluster = TransitiveAndReflexiveClosure<Node>(
node => from n in node.InputNeigh where n.State == node.State select n,
someNode);
现在您可以简单地询问集群的大小(如果需要的话)。
(请更改 InputNeigh
的名称。缩写很不酷,哟,除非你年满 13 岁。)
关于c# - 在计算图中的簇大小时如何避免无限循环?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19103540/
我是 PHP 新手。我一直在脚本中使用 for 循环、while 循环、foreach 循环。我想知道 哪个性能更好? 选择循环的标准是什么? 当我们在另一个循环中循环时应该使用哪个? 我一直想知道要
我在高中的编程课上,我的作业是制作一个基本的小计和顶级计算器,但我在一家餐馆工作,所以制作一个只能让你在一种食物中读到。因此,我尝试让它能够接收多种食品并将它们添加到一个价格变量中。抱歉,如果某些代码
这是我正在学习的一本教科书。 var ingredients = ["eggs", "milk", "flour", "sugar", "baking soda", "baking powder",
我正在从字符串中提取数字并将其传递给函数。我想给它加 1,然后返回字符串,同时保留前导零。我可以使用 while 循环来完成此操作,但不能使用 for 循环。 for 循环只是跳过零。 var add
编辑:我已经在程序的输出中进行了编辑。 该程序要求估计给定值 mu。用户给出一个值 mu,同时还提供了四个不等于 1 的不同数字(称为 w、x、y、z)。然后,程序尝试使用 de Jaeger 公式找
我正在编写一个算法,该算法对一个整数数组从末尾到开头执行一个大循环,其中包含一个 if 条件。第一次条件为假时,循环可以终止。 因此,对于 for 循环,如果条件为假,它会继续迭代并进行简单的变量更改
现在我已经习惯了在内存非常有限的情况下进行编程,但我没有答案的一个问题是:哪个内存效率更高;- for(;;) 或 while() ?还是它们可以平等互换?如果有的话,还要对效率问题发表评论! 最佳答
这个问题已经有答案了: How do I compare strings in Java? (23 个回答) 已关闭 8 年前。 我正在尝试创建一个小程序,我可以在其中读取该程序的单词。如果单词有 6
这个问题在这里已经有了答案: python : list index out of range error while iteratively popping elements (12 个答案) 关
我正在尝试向用户请求 4 到 10 之间的整数。如果他们回答超出该范围,它将进入循环。当用户第一次正确输入数字时,它不会中断并继续执行 else 语句。如果用户在 else 语句中正确输入数字,它将正
我尝试创建一个带有嵌套 foreach 循环的列表。第一个循环是循环一些数字,第二个循环是循环日期。我想给一个日期写一个数字。所以还有另一个功能来检查它。但结果是数字多次写入日期。 Out 是这样的:
我想要做的事情是使用循环创建一个数组,然后在另一个类中调用该数组,这不会做,也可能永远不会做。解决这个问题最好的方法是什么?我已经寻找了所有解决方案,但它们无法编译。感谢您的帮助。 import ja
我尝试创建一个带有嵌套 foreach 循环的列表。第一个循环是循环一些数字,第二个循环是循环日期。我想给一个日期写一个数字。所以还有另一个功能来检查它。但结果是数字多次写入日期。 Out 是这样的:
我正在模拟一家快餐店三个多小时。这三个小时分为 18 个间隔,每个间隔 600 秒。每个间隔都会输出有关这 600 秒内发生的情况的统计信息。 我原来的结构是这样的: int i; for (i=0;
这个问题已经有答案了: IE8 for...in enumerator (3 个回答) How do I check if an object has a specific property in J
哪个对性能更好?这可能与其他编程语言不一致,所以如果它们不同,或者如果你能用你对特定语言的知识回答我的问题,请解释。 我将使用 c++ 作为示例,但我想知道它在 java、c 或任何其他主流语言中的工
这个问题不太可能帮助任何 future 的访问者;它只与一个小的地理区域、一个特定的时间点或一个非常狭窄的情况有关,这些情况并不普遍适用于互联网的全局受众。为了帮助使这个问题更广泛地适用,visit
我是 C 编程和编写代码的新手,以确定 M 测试用例的质因数分解。如果我一次只扫描一次,该功能本身就可以工作,但是当我尝试执行 M 次时却惨遭失败。 我不知道为什么 scanf() 循环有问题。 in
这个问题已经有答案了: JavaScript by reference vs. by value [duplicate] (4 个回答) 已关闭 3 年前。 我在使用 TSlint 时遇到问题,并且理
我尝试在下面的代码中添加 foreach 或 for 循环,以便为 Charts.js 创建多个数据集。这将允许我在此折线图上创建多条线。 我有一个 PHP 对象,我可以对其进行编码以稍后填充变量,但
我是一名优秀的程序员,十分优秀!