如何检查树结构中是否是后代?

时间:2011-09-06 06:09:58

标签: c# algorithm tree

我有以下结构:

 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));

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

3 个答案:

答案 0 :(得分:2)

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

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;
        }
    }
}

答案 1 :(得分:1)

你可以这样做:

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<long, Employee>

答案 2 :(得分:1)

当处理对象模型中的树时,如果对象具有Children,我发现它更有用。虽然现在更容易维护父母。实际上,您可以将树抽象为通用接口,或两个:

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; }
}

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

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,
Berryl