- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我有以下 Tarjan 算法的(递归)实现来查找图中的强连通分量,它工作正常:
public class StronglyConnectedComponents
{
public static List<List<int>> Search(Graph graph)
{
StronglyConnectedComponents scc = new StronglyConnectedComponents();
return scc.Tarjan(graph);
}
private int preCount;
private int[] low;
private bool[] visited;
private Graph graph;
private List<List<int>> stronglyConnectedComponents = new List<List<int>>();
private Stack<int> stack = new Stack<int>();
public List<List<int>> Tarjan(Graph graph)
{
this.graph = graph;
low = new int[graph.VertexCount];
visited = new bool[graph.VertexCount];
for (int v = 0; v < graph.VertexCount; v++) if (!visited[v]) DFS(v);
return stronglyConnectedComponents;
}
public void DFS(int v)
{
low[v] = preCount++;
visited[v] = true;
stack.Push(v);
int min = low[v];
int edgeCount = graph.OutgoingEdgeCount(v);
for (int i = 0; i < edgeCount; i++)
{
var edge = graph.OutgoingEdge(v, i);
int target = edge.Target;
if (!visited[target]) DFS(target);
if (low[target] < min) min = low[target];
}
if (min < low[v])
{
low[v] = min;
return;
}
List<int> component = new List<int>();
int w;
do
{
w = stack.Pop();
component.Add(w);
low[w] = graph.VertexCount;
} while (w != v);
stronglyConnectedComponents.Add(component);
}
}
但是在大图上,递归版本显然会抛出 StackOverflowException。因此我想使算法成为非递归的。
我尝试用以下(非递归)函数替换函数 DFS
,但该算法不再有效。有人可以帮忙吗?
private void DFS2(int vertex)
{
bool[] visited = new bool[graph.VertexCount];
Stack<int> stack = new Stack<int>();
stack.Push(vertex);
int min = low[vertex];
while (stack.Count > 0)
{
int v = stack.Pop();
if (visited[v]) continue;
visited[v] = true;
int edgeCount = graph.OutgoingEdgeCount(v);
for (int i = 0; i < edgeCount; i++)
{
int target = graph.OutgoingEdge(v, i).Target;
stack.Push(target);
if (low[target] < min) min = low[target];
}
}
if (min < low[vertex])
{
low[vertex] = min;
return;
}
List<int> component = new List<int>();
int w;
do
{
w = stack.Pop();
component.Add(w);
low[w] = graph.VertexCount;
} while (w != vertex);
stronglyConnectedComponents.Add(component);
}
下面的代码显示了测试:
public void CanFindStronglyConnectedComponents()
{
Graph graph = new Graph(8);
graph.AddEdge(0, 1);
graph.AddEdge(1, 2);
graph.AddEdge(2, 3);
graph.AddEdge(3, 2);
graph.AddEdge(3, 7);
graph.AddEdge(7, 3);
graph.AddEdge(2, 6);
graph.AddEdge(7, 6);
graph.AddEdge(5, 6);
graph.AddEdge(6, 5);
graph.AddEdge(1, 5);
graph.AddEdge(4, 5);
graph.AddEdge(4, 0);
graph.AddEdge(1, 4);
var scc = StronglyConnectedComponents.Search(graph);
Assert.AreEqual(3, scc.Count);
Assert.IsTrue(SetsEqual(Set(5, 6), scc[0]));
Assert.IsTrue(SetsEqual(Set(7, 3, 2), scc[1]));
Assert.IsTrue(SetsEqual(Set(4, 1, 0), scc[2]));
}
private IEnumerable<int> Set(params int[] set) => set;
private bool SetsEqual(IEnumerable<int> set1, IEnumerable<int> set2)
{
if (set1.Count() != set2.Count()) return false;
return set1.Intersect(set2).Count() == set1.Count();
}
最佳答案
这里是原始递归实现的直接非递归翻译(假设它是正确的):
public static List<List<int>> Search(Graph graph)
{
var stronglyConnectedComponents = new List<List<int>>();
int preCount = 0;
var low = new int[graph.VertexCount];
var visited = new bool[graph.VertexCount];
var stack = new Stack<int>();
var minStack = new Stack<int>();
var enumeratorStack = new Stack<IEnumerator<int>>();
var enumerator = Enumerable.Range(0, graph.VertexCount).GetEnumerator();
while (true)
{
if (enumerator.MoveNext())
{
int v = enumerator.Current;
if (!visited[v])
{
low[v] = preCount++;
visited[v] = true;
stack.Push(v);
int min = low[v];
// Level down
minStack.Push(min);
enumeratorStack.Push(enumerator);
enumerator = Enumerable.Range(0, graph.OutgoingEdgeCount(v))
.Select(i => graph.OutgoingEdge(v, i).Target)
.GetEnumerator();
}
else if (minStack.Count > 0)
{
int min = minStack.Pop();
if (low[v] < min) min = low[v];
minStack.Push(min);
}
}
else
{
// Level up
if (enumeratorStack.Count == 0) break;
enumerator = enumeratorStack.Pop();
int v = enumerator.Current;
int min = minStack.Pop();
if (min < low[v])
{
low[v] = min;
}
else
{
List<int> component = new List<int>();
int w;
do
{
w = stack.Pop();
component.Add(w);
low[w] = graph.VertexCount;
} while (w != v);
stronglyConnectedComponents.Add(component);
}
if (minStack.Count > 0)
{
min = minStack.Pop();
if (low[v] < min) min = low[v];
minStack.Push(min);
}
}
}
return stronglyConnectedComponents;
}
像往常一样,对于这种直接翻译,您需要一个显式堆栈来存储从递归调用“返回”后需要恢复的状态。在这种情况下,它是级别顶点枚举器和 min
变量。
请注意,现有的 stack
变量不能使用,因为当处理顶点被推到那里时,它并不总是在退出时弹出(递归实现中的 return
行) ,这是该算法的特定要求。
关于c# - Tarjan 算法的非递归版本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46511682/
本篇包含 tarjan 求强连通分量、边双连通分量、割点 部分, tarjan 求点双连通分量、桥(割边)在下一篇。 伟大的 Robert Tarjan 创造了众多被人们所熟知的算法及数据
我继续并 implemented textbook version of Tarjan's SCC algorithm在斯卡拉。然而,我不喜欢这个代码——它是非常命令式/程序性的,有很多变异状态和簿记
我有以下 Tarjan 算法的(递归)实现来查找图中的强连通分量,它工作正常: public class StronglyConnectedComponents { public static
我正在阅读 Tarjan's paper on scc . 在论文中,给定顶点的lowlink定义为: LOWLINK (v) is the smallest vertex which is in t
我最近学习了线性时间算法来计算图中的连接点。我的实现在 Online Judge 测试数据上正确运行,因此代码没有问题。然而,我似乎对 DFS 运行中同一个清晰点出现不止一个有一些困难。让我解释一下
我正在尝试实现 Tarjan 的强连通图算法 ( https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algo
每当我在任何图上运行 tarjans 算法时,它总是声称有一个循环,例如这个图: A -> B -> C 算法会告诉我有一个循环: [a] [b] 当有一个循环时,例如: A -> B -> C ->
我已经尝试从维基百科学习 Tarjan 的算法 3 个小时了,但我就是无法理解它。 :( http://en.wikipedia.org/wiki/Tarjan's_strongly_connecte
我正在尝试在标准 ML 中实现图算法,但前提是唯一允许的效果是改变引用单元格。禁止异常(exception)和不终止。标准 ML 本身对这个问题并不重要。我会接受任何其他类型化编程语言的答案,只要它满
我已经按照 Wikipedia's article 实现了 Tarjan 的算法但是我遇到了问题。我要做的是找到所有大小大于 1 的强连通分量。使用较小的输入,一切正常,但是,当使用 input.tx
我正在从这里学习 tarjan 的算法 Tarjan ,我有两个问题: 我们如何使用堆栈找到强连通组件? 为什么从以 V 为根的子树到它的祖先的后代应该没有回边? 最佳答案 要回答第二个问题,可以这样
我在学习Tarjan's algorithm for strongly-connected components它的工作方式对我来说很清楚。无论如何,有一行我不明白: // Consider succ
我正在尝试使用 Tarjan 算法确定有向图中的循环,该算法在他 1972 年 9 月的研究论文“有向图的基本电路枚举”中提出。 我正在使用 Python 编写算法代码,并使用邻接表来跟踪节点之间的关
我已经通过 http://learn.yancyparedes.net/2012/03/strongly-connected-components-using-tarjans-algorithm/ 的
我根据 wikipedia 实现了 Tarjan 的强连通分量算法,在 Python 中,但它不起作用。该算法很短,我找不到任何区别,所以我不知道为什么它不起作用。我试图查看原始论文,但找不到。 这是
我正在尝试翻译递归 python code for tarjan algorithm到 scala,尤其是这部分: def tarjan_recursive(g): S = []
这个问题在这里已经有了答案: Compile Error: Cannot Find Symbol (2 个答案) 关闭 7 年前。 我正在尝试从 wikipedia 运行 Tarjan java 实
我正在 Cheriton-Tarjan 算法中搜索加权最小生成树,时间复杂度为 O(m*loglogn)。但我无法在任何地方找到它。有人可以向我解释算法或告诉我在哪里可以找到它的链接吗? 最佳答案 是
我正在阅读 Donal B.Johnson 关于在有向图中查找所有基本电路的论文,http://www.cs.tufts.edu/comp/150GA/homeworks/hw1/Johnson%20
我正在阅读以下链接中的代码 http://www.cosc.canterbury.ac.nz/tad.takaoka/alg/graphalg/sc.txt我一直碰到“低链接”这个词,我不知道它是什么
我是一名优秀的程序员,十分优秀!