Tarjan循环检测帮助C#

Tarjan循环检测帮助C#,c#,algorithm,cycle,directed-graph,tarjans-algorithm,C#,Algorithm,Cycle,Directed Graph,Tarjans Algorithm,下面是tarjan循环检测的C#实现 算法如下所示: 公共类TarjanCycleDetect { 私有静态列表强连接组件; 私有静态堆栈; 私有静态int索引; 私有静态数据包; 公共静态列表检测周期(DepGraph) { StronglyConnectedComponents=新列表(); 指数=0; S=新堆栈(); dg=g; foreach(g.顶点中的顶点v) { 如果(v.指数x.Key) .Where(x=>x.Count()>1) .Select(x=>x.ToList()

下面是tarjan循环检测的C#实现

算法如下所示:

公共类TarjanCycleDetect
{
私有静态列表强连接组件;
私有静态堆栈;
私有静态int索引;
私有静态数据包;
公共静态列表检测周期(DepGraph)
{
StronglyConnectedComponents=新列表();
指数=0;
S=新堆栈();
dg=g;
foreach(g.顶点中的顶点v)
{
如果(v.指数<0)
{
strong连接(v);
}
}
返回强连接组件;
}
专用静态连接(顶点v)
{
v、 指数=指数;
v、 lowlink=指数;
索引++;
S.Push(v);
foreach(v.dependencies中的顶点w)
{
如果(w.指数<0)
{
strong连接(w);
v、 lowlink=数学最小值(v.lowlink,w.lowlink);
}
否则,如果(S.包含(w))
{
v、 lowlink=数学最小值(v.lowlink,w.index);
}
}
if(v.lowlink==v.index)
{
列表scc=新列表();
顶点w;
做
{
w=S.Pop();
新增专用条款(w);
}而(v!=w);
strong连接组件。添加(scc);
}
}
请注意,degraph只是一个顶点列表。顶点有一个表示边的其他顶点列表。此外,index和lowlink被初始化为-1


编辑:这是有效的…我只是误解了结果。

上述事实是正确的,我不理解强连接组件是什么。我希望函数返回一个空的强连接组件列表,但它返回的是一个单节点列表


我相信上面的方法是有效的。如果需要,请随意使用!

自2008年起,quickgraph已支持此算法。有关实现,请参阅
StronglyConnectedComponents算法
类,或
AlgorithmExtensions.StronglyConnectedComponents
方法,了解使用快捷方式

例如:

// Initialize result dictionary
IDictionary<string, int> comps = new Dictionary<string, int>();

// Run the algorithm
graph.StronglyConnectedComponents(out comps);

// Group and filter the dictionary
var cycles = comps
    .GroupBy(x => x.Value, x => x.Key)
    .Where(x => x.Count() > 1)
    .Select(x => x.ToList())
//初始化结果字典
IDictionary comps=新字典();
//运行算法
图.strong连接组件(外部组件);
//对字典进行分组和筛选
var周期=补偿
.GroupBy(x=>x.Value,x=>x.Key)
.Where(x=>x.Count()>1)
.Select(x=>x.ToList())

如果有人想快速使用上述示例,则该示例不起作用。另外请注意,它是基于堆栈的,如果您不给出最琐碎的图形,它将引爆堆栈。下面是一个单元测试的工作示例,该示例对Tarjan wikipedia页面上显示的图形进行建模:

public class Vertex
{
    public int Id { get;set; }
    public int Index { get; set; }
    public int Lowlink { get; set; }

    public HashSet<Vertex> Dependencies { get; set; }

    public Vertex()
    {
        Id = -1;
        Index = -1;
        Lowlink = -1;
        Dependencies = new HashSet<Vertex>();
    }

    public override string ToString()
    {
        return string.Format("Vertex Id {0}", Id);
    }

    public override int GetHashCode()
    {
        return Id;
    }

    public override bool Equals(object obj)
    {
        if (obj == null)
            return false;

        Vertex other = obj as Vertex;

        if (other == null)
            return false;

        return Id == other.Id;
    }
}

public class TarjanCycleDetectStack
{
    protected List<List<Vertex>> _StronglyConnectedComponents;
    protected Stack<Vertex> _Stack;
    protected int _Index;

    public List<List<Vertex>> DetectCycle(List<Vertex> graph_nodes)
    {
        _StronglyConnectedComponents = new List<List<Vertex>>();

        _Index = 0;
        _Stack = new Stack<Vertex>();

        foreach (Vertex v in graph_nodes)
        {
            if (v.Index < 0)
            {
                StronglyConnect(v);
            }
        }

        return _StronglyConnectedComponents;
    }

    private void StronglyConnect(Vertex v)
    {
        v.Index = _Index;
        v.Lowlink = _Index;

        _Index++;
        _Stack.Push(v);

        foreach (Vertex w in v.Dependencies)
        {
            if (w.Index < 0)
            {
                StronglyConnect(w);
                v.Lowlink = Math.Min(v.Lowlink, w.Lowlink);
            }
            else if (_Stack.Contains(w))
            {
                v.Lowlink = Math.Min(v.Lowlink, w.Index);
            }
        }

        if (v.Lowlink == v.Index)
        {
            List<Vertex> cycle = new List<Vertex>();
            Vertex w;

            do
            {
                w = _Stack.Pop();
                cycle.Add(w);
            } while (v != w);

            _StronglyConnectedComponents.Add(cycle);
        }
    }
}

    [TestMethod()]
    public void TarjanStackTest()
    {
        // tests simple model presented on https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
        var graph_nodes = new List<Vertex>();

        var v1 = new Vertex() { Id = 1 };
        var v2 = new Vertex() { Id = 2 };
        var v3 = new Vertex() { Id = 3 };
        var v4 = new Vertex() { Id = 4 };
        var v5 = new Vertex() { Id = 5 };
        var v6 = new Vertex() { Id = 6 };
        var v7 = new Vertex() { Id = 7 };
        var v8 = new Vertex() { Id = 8 };

        v1.Dependencies.Add(v2);
        v2.Dependencies.Add(v3);
        v3.Dependencies.Add(v1);
        v4.Dependencies.Add(v3);
        v4.Dependencies.Add(v5);
        v5.Dependencies.Add(v4);
        v5.Dependencies.Add(v6);
        v6.Dependencies.Add(v3);
        v6.Dependencies.Add(v7);
        v7.Dependencies.Add(v6);
        v8.Dependencies.Add(v7);
        v8.Dependencies.Add(v5);
        v8.Dependencies.Add(v8);

        graph_nodes.Add(v1);
        graph_nodes.Add(v2);
        graph_nodes.Add(v3);
        graph_nodes.Add(v4);
        graph_nodes.Add(v5);
        graph_nodes.Add(v6);
        graph_nodes.Add(v7);
        graph_nodes.Add(v8);

        var tcd = new TarjanCycleDetectStack();
        var cycle_list = tcd.DetectCycle(graph_nodes);

        Assert.IsTrue(cycle_list.Count == 4);
    }
公共类顶点
{
公共int Id{get;set;}
公共int索引{get;set;}
公共int低位链接{get;set;}
公共哈希集依赖项{get;set;}
公共顶点()
{
Id=-1;
指数=-1;
Lowlink=-1;
依赖项=新的HashSet();
}
公共重写字符串ToString()
{
返回string.Format(“顶点Id{0}”,Id);
}
公共覆盖int GetHashCode()
{
返回Id;
}
公共覆盖布尔等于(对象对象对象)
{
if(obj==null)
返回false;
顶点其他=obj作为顶点;
如果(其他==null)
返回false;
返回Id==other.Id;
}
}
公共类TarjanCycleDetectStack
{
受保护列表\u strong连接组件;
受保护堆栈(u堆栈);;
受保护的整数指数;
公共列表检测循环(列表图_节点)
{
_StronglyConnectedComponents=新列表();
_指数=0;
_堆栈=新堆栈();
foreach(图_节点中的顶点v)
{
如果(v.指数<0)
{
强连接(v);
}
}
返回_strong连接的组件;
}
私有void strong连接(顶点v)
{
v、 指数=_指数;
v、 Lowlink=_指数;
_索引++;
_栈推(v);
foreach(v.Dependencies中的顶点w)
{
如果(w.指数<0)
{
强连接(w);
v、 Lowlink=数学最小值(v.Lowlink,w.Lowlink);
}
else如果(_堆栈包含(w))
{
v、 Lowlink=数学最小值(v.Lowlink,w.Index);
}
}
if(v.Lowlink==v.Index)
{
列表周期=新列表();
顶点w;
做
{
w=_Stack.Pop();
循环。添加(w);
}而(v!=w);
_strong连接组件。添加(循环);
}
}
}
[TestMethod()]
公共无效测试()
{
//测试简单的模型https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
var graph_nodes=新列表();
var v1=新顶点(){Id=1};
var v2=新顶点(){Id=2};
var v3=新顶点(){Id=3};
var v4=新顶点(){Id=4};
var v5=新顶点(){Id=5};
var v6=新顶点(){Id=6};
var v7=新顶点(){Id=7};
var v8=新顶点(){Id=8};
v1.Dependencies.Add(v2);
v2.Dependencies.Add(v3);
v3.Dependencies.Add(v1);
v4.Dependencies.Add(v3);
v4.Dependencies.Add(v5);
v5.Dependencies.Add(v4);
v5.Dependencies.Add(v6);
v6.Dependencies.Add(v3);
v6.Dependencies.Add(v7);
v7.Dependencies.Add(v6);
v8.Dependencies.Add(v7);
v8.副驾驶
public class Vertex
{
    public int Id { get;set; }
    public int Index { get; set; }
    public int Lowlink { get; set; }

    public HashSet<Vertex> Dependencies { get; set; }

    public Vertex()
    {
        Id = -1;
        Index = -1;
        Lowlink = -1;
        Dependencies = new HashSet<Vertex>();
    }

    public override string ToString()
    {
        return string.Format("Vertex Id {0}", Id);
    }

    public override int GetHashCode()
    {
        return Id;
    }

    public override bool Equals(object obj)
    {
        if (obj == null)
            return false;

        Vertex other = obj as Vertex;

        if (other == null)
            return false;

        return Id == other.Id;
    }
}

public class TarjanCycleDetectStack
{
    protected List<List<Vertex>> _StronglyConnectedComponents;
    protected Stack<Vertex> _Stack;
    protected int _Index;

    public List<List<Vertex>> DetectCycle(List<Vertex> graph_nodes)
    {
        _StronglyConnectedComponents = new List<List<Vertex>>();

        _Index = 0;
        _Stack = new Stack<Vertex>();

        foreach (Vertex v in graph_nodes)
        {
            if (v.Index < 0)
            {
                StronglyConnect(v);
            }
        }

        return _StronglyConnectedComponents;
    }

    private void StronglyConnect(Vertex v)
    {
        v.Index = _Index;
        v.Lowlink = _Index;

        _Index++;
        _Stack.Push(v);

        foreach (Vertex w in v.Dependencies)
        {
            if (w.Index < 0)
            {
                StronglyConnect(w);
                v.Lowlink = Math.Min(v.Lowlink, w.Lowlink);
            }
            else if (_Stack.Contains(w))
            {
                v.Lowlink = Math.Min(v.Lowlink, w.Index);
            }
        }

        if (v.Lowlink == v.Index)
        {
            List<Vertex> cycle = new List<Vertex>();
            Vertex w;

            do
            {
                w = _Stack.Pop();
                cycle.Add(w);
            } while (v != w);

            _StronglyConnectedComponents.Add(cycle);
        }
    }
}

    [TestMethod()]
    public void TarjanStackTest()
    {
        // tests simple model presented on https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
        var graph_nodes = new List<Vertex>();

        var v1 = new Vertex() { Id = 1 };
        var v2 = new Vertex() { Id = 2 };
        var v3 = new Vertex() { Id = 3 };
        var v4 = new Vertex() { Id = 4 };
        var v5 = new Vertex() { Id = 5 };
        var v6 = new Vertex() { Id = 6 };
        var v7 = new Vertex() { Id = 7 };
        var v8 = new Vertex() { Id = 8 };

        v1.Dependencies.Add(v2);
        v2.Dependencies.Add(v3);
        v3.Dependencies.Add(v1);
        v4.Dependencies.Add(v3);
        v4.Dependencies.Add(v5);
        v5.Dependencies.Add(v4);
        v5.Dependencies.Add(v6);
        v6.Dependencies.Add(v3);
        v6.Dependencies.Add(v7);
        v7.Dependencies.Add(v6);
        v8.Dependencies.Add(v7);
        v8.Dependencies.Add(v5);
        v8.Dependencies.Add(v8);

        graph_nodes.Add(v1);
        graph_nodes.Add(v2);
        graph_nodes.Add(v3);
        graph_nodes.Add(v4);
        graph_nodes.Add(v5);
        graph_nodes.Add(v6);
        graph_nodes.Add(v7);
        graph_nodes.Add(v8);

        var tcd = new TarjanCycleDetectStack();
        var cycle_list = tcd.DetectCycle(graph_nodes);

        Assert.IsTrue(cycle_list.Count == 4);
    }