在这种情况下如何检查链表是否有循环

时间:2019-07-02 06:35:44

标签: c# .net linked-list

必须创建一个链接列表,在此我们将添加相互依赖的部门。

输入将是部门名称,然后是它们所依赖的部门名称,有些输入可能后跟空字符串,这意味着它们不依赖任何部门。

因此输出将首先是第二部门,依此类推

  1. 一个部门不能依靠它自己(照料)

  2. 必须查找部门是否具有周期性依赖性(问题)

输入

销售

营销帐户

金融销售

所以输出将是

销售金融帐户营销

输入

销售营销

营销帐户

帐户销售

输出

错误,它不能具有循环依赖性

尝试以下代码,以查看我的链表中是否有循环

private bool DoesItHasLoops()
        {
            var fast = myLinkedList.First;
            var slow = myLinkedList.First;
            while (fast != null && fast.Next != null)
            {
                fast = fast.Next.Next;
                slow = slow.Next;
                if (slow == fast)
                    return true;


            }
            return false;
        }

它不起作用,也找不到循环。

下面的代码是我在链接列表中添加字符串的方式。

private LinkedList<strings> myLinkedList;

public void AddDepartments(string[] input)
{
   if (input.Count() > 1)
      {
        if (myLinkedList.Contains(input[0]))  
         {

          myLinkedList.AddBefore(adjList.Find(input[0]), input[1]);

          }
        else
         {
          myLinkedList.AddLast(input[1]);                            
          myLinkedList.AddLast(input[0]);
         }
      }
    else
    {
     myLinkedList.AddLast(input[0]);
     myLinkedList.AddLast(string.empty());

     }
}

这对所有情况都有效,只有循环情况不起作用

2 个答案:

答案 0 :(得分:0)

我建议您稍微更改一下体系结构。我将使用LinkedList,而不是使用将所有内容都存储在Dictionary中的结构。这样,您可以轻松地将部门与其所依赖的部门联系起来。

因此您将拥有一个Dictionary<string, List<string>>,其中键是部门及其依赖的部门的值:

private bool DoesItHasLoops(Dictionary<string, List<string>> departmentWithDepending)
{
    HashSet<string> checkedDepartments = new HashSet<string>();

    foreach (var department in departmentWithDepending)
    {
        checkedDepartments.Add(department.Key);
        if (HasConflict(department.Value, departmentWithDepending, checkedDepartments))
        {
            return true;
        }
        checkedDepartments.Clear();
    }
    return false;
}

private bool HasConflict(List<string> dependentDepartments,
    Dictionary<string, List<string>> departmentWithDepending,
    HashSet<string> checkedDepartments)
{
    foreach (var currentDepartment in dependentDepartments)
    {
        //Checks if this department was already checked, if yes you got a loop
        if (checkedDepartments.Contains(currentDepartment))
        {
            return true;
        }
        else
        {
            //Checks if the current department has a dependency
            if (departmentWithDepending.ContainsKey(currentDepartment))
            {
                //marks the current department as checked and and checks if the department the current department depends on has any conflicts(loops)
                checkedDepartments.Add(currentDepartment);
                if (HasConflict(departmentWithDepending[currentDepartment], departmentWithDepending, checkedDepartments))
                {
                    return true;
                }
                else
                {
                    checkedDepartments.Remove(currentDepartment);
                }
            }
        }
    }
    return false;
}

要找到这种循环并不是一件容易的事,上面的方法有望奏效,但我尚未对其进行测试。如果您有任何疑问,可以在评论部分提出,因为我明白了为什么这段代码可能难以理解。

顺便说一句,我正在从内部调用HasConflict(...)以查找任何下一个冲突。通常我建议不要这样做,因为这样会导致无限循环。仅当您100%确信它不可能卡住时,才应该这样做。

编辑:

departments: a, b, c, d

dependencies:
a (depends on) b, c
b (depends on) (nothing)
c (depends on) d
d (depends on) a, b

dependencies that are fine:
a -> b 
a -> c -> d -> b
c -> d -> b
d -> b

dependencies that would cause a conflict:
a -> c -> d -> a
c -> d -> a -> c
d -> a -> c -> d

答案 1 :(得分:0)

在我看来,识别这些循环的最简单方法是找到那些在某个点同时也将具有依赖关系的部门列为依赖关系的部分,并遍历两者之间的依赖关系链以查看它们是否相互连接。也就是说,您的体系结构似乎有点过时了。我将创建一个对象来保存部门及其相关性列表以及是否有这样的循环引用的标志:

public class Department
{
    public int Id { get; set; }
    public string Name { get; set; }
    public IList<int> Dependencies { get; set; }
    public bool HasCircularReferences { get; set; } 
}

然后,您传递部门列表并遍历每个部门,并找到将该部门列为依赖项的其他部门。然后,您可以通过依赖关系链中的内容进行重新工作,以查看是否最终返回到当前部门。您可以使用这样的循环(请注意,这是我在控制台应用程序中对其进行测试时的静态方法):

private static void GetDependents(IList<int> dependencies, int seed)
{
    foreach (var dependent in dependencies)
    {
        var dependentDept = departments.Where(d => d.Id == dependent).FirstOrDefault();
        if (dependentDept.Dependencies.Count > 0)
        {
            if (dependencies.Contains(seed) || dependentDept.HasCircularReferences)
            {
                SetCircularReferenceFlag(seed, true);
                break;
            }
            GetDependents(dependentDept.Dependencies, seed);
        }
        else
        {
            SetCircularReferenceFlag(seed, false);
            break;
        }
    }
}

这将使用SetCircularReferenceFlag方法在部门上设置HasCircularReferences标志,该方法是:

private static void SetCircularReferenceFlag(int departmentId, bool hasCircularReferences)
{
    var seedDept = departments.Where(d => d.Id == departmentId).FirstOrDefault();
    seedDept.HasCircularReferences = hasCircularReferences;
}

然后可以为列表中的每个部门调用GetDependents方法,如下所示:

foreach (var department in departments)
{
    GetDependents(department.Dependencies, department.Id);
}

使用上面定义的Department对象将部门设置为如下所示:

private static List<Department> departments = new List<Department>
{
    new Department
    {
        Id = 1,
        Name = "sales",
        Dependencies = new List<int>{ 2 }
    },
    new Department
    {
        Id = 2,
        Name = "accounts",
        Dependencies = new List<int>{ 3 }
    },
    new Department
    {
        Id = 3,
        Name = "marketing",
        Dependencies = new List<int>{ 1 }
     },
     new Department
     {
        Id = 4,
        Name = "finance",
        Dependencies = new List<int>{ 1 }
     }
 };

通过控制台应用程序运行此命令时,会得到以下结果:

enter image description here