【问题标题】:How to check if is descendant within tree structure?如何检查树结构中是否是后代?
【发布时间】:2011-09-06 06:09:57
【问题描述】:

我有以下结构:

 class Employee
        {
            public long Id { get; set; }

            public long? ParentId { get; set; }

            public Employee(long id, long? parentId)
            {
                Id = id;
                Parent_Id = parentId;
            }
        }

让我们构建一些树状结构:

        var employees = new List<Employee>();

        employees.Add(new Employee(1 , null));
        employees.Add(new Employee(2 , 1));
        employees.Add(new Employee(3 , 2));

如何检查(使用 C#)Id=1 的员工是否是此列表中 Id=3 的员工的父级?树结构可能要复杂得多。

【问题讨论】:

    标签: c# algorithm tree


    【解决方案1】:

    要检查是否是后代,您可以遍历树并查看是否找到他:

    static bool GetIsDescendant(long idChild, long idAncestor, IEnumerable<Employee> employees)
    {
        return GetAncestors(idChild, employees).Any(t => t.Id == idAncestor);
    }
    
    static IEnumerable<Employee> GetAncestors(long idEmployee, IEnumerable<Employee> employees)
    {
        var employee = employees.SingleOrDefault(e => e.Id == idEmployee);
    
        if (employee == null)
        {
            yield break;
        }
    
        while (employee.ParentId.HasValue)
        {
            var parent = employees.SingleOrDefault(e => e.Id == employee.ParentId.Value);
    
            if (parent == null)
            {
                yield break;
            }
            else
            {
                employee = parent;
                yield return parent;
            }
        }
    }
    

    【讨论】:

    • 问题是一名员工是否是另一名员工的父母,而不是后代或前任。
    • 标题是“如何检查树结构中是否有后代?”
    【解决方案2】:

    你可以这样做:

    static bool IsParent(
        IEnumerable<Employee> employees, long potentialParentId, long potentialChildId)
    {
        var potentialChild = employees.SingleOrDefault(e => e.Id == potentialChildId);
        return potentialChild != null && potentialChild.ParentId == potentialParentId;
    }
    

    但是这样做可能会非常缓慢,尤其是在您有很多员工的情况下。如果你想通过Id快速查找,可以使用Dictionary&lt;long, Employee&gt;

    【讨论】:

      【解决方案3】:

      在对象模型中处理树时,我发现对象有子对象会更有用。尽管像您一样维护父级仍然更容易。实际上,您可以将树抽象为一个通用接口,或者两个:

      public interface IHaveChildren<out T> where T:IHaveChildren<T>
      {
          /// <summary>Gets the children.</summary>
          IEnumerable<T> Children { get; }
      }
      
      public interface IHaveFamily<out T> : IHaveChildren<T> where T : IHaveChildren<T>
      {
          /// <summary>Gets the Parent.</summary>
          T Parent { get; }
      }
      

      现在您可以设置许多有趣且有用的扩展来获取树信息,而不必让您可怜的 Employee 类也不必担心这个!下面是两个利用这些接口的扩展。

      public static class HeirarchyExtensions
      {
      
          public static bool IsAncestorOf<T>(this IHaveFamily<T> instance1, IHaveFamily<T> instance2) where T : IHaveFamily<T>
          {
              if(instance1.IsLeaf()) return false;
      
              foreach (var child in instance1.Children)
              {
                  if (child.Equals(instance2)) return true;
                  return instance1.IsAncestorOf(child);
              }
              return false;
          }
      
          public static IEnumerable<T> GetDescendents<T>(this IHaveFamily<T> instance) where T : IHaveFamily<T>
          {
              var result = instance.Children;
              if(!result.Any()) 
                  return result;
              foreach (var child in instance.Children) {
                  result = result.Concat(child.Children);
              }
              return result;
          }
      
      }
      

      HTH,
      浆果

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-05-09
        • 2021-03-22
        • 1970-01-01
        • 2019-09-17
        • 1970-01-01
        • 1970-01-01
        • 2020-11-21
        • 2015-04-23
        相关资源
        最近更新 更多