2016-03-22 92 views
0

我有什么应该是一个相当无足轻重的问题,但我想确保我在.Net 4.5中以最“优雅”的方式做到这一点,我想一些比我更聪明的人的意见。通用树结构 - 如何填充组织结构图

我有一个类,它表示一个通用的树结构,例如:

public class TreeNode<T> 
    { 
     List<TreeNode<T>> Children; 

     T Item {get;set;} 

     public TreeNode (T item) 
     { 
      Item = item; 
     } 

     public TreeNode<T> AddChild(T item) 
     { 
      TreeNode<T> nodeItem = new TreeNode<T>(item); 
      Children.Add(nodeItem); 
      return nodeItem; 
     } 
    } 

现在,我代表该组织的雇员一个Person类。每个Person对象都有一个指向其上级的IDBossID

多位员工可以拥有相同的老板,因此我试图用此树结构创建组织结构图。

顶部节点将是Person对象,其中BossID为空(它是一个int?)。我可以快速获得LINQ。

这是下一步令我困惑的一点。有多种方法,但对我来说似乎有点草率,我知道必须有一种更容易/更优雅的方式来填充组织结构图的其余部分。

所以现在我有一个通用对象List<Person>持有所有员工,其各种BossID和这个通用的树结构,我可以添加子节点。

这都是非常基本的,但是填充树的正确顺序是什么?我递归地应该迭代线?我知道这里涉及回溯,这是我陷入困境的地方。

我很抱歉,我的背景不在计算机科学,如果是我意识到树结构,链表和其他一切都是微不足道的东西。但这是我第一次尝试,我想看看它是如何正确完成的。

我很欣赏任何指导。

+0

所以基本上你的问题是如何创建组织树,因为你有人的名单? –

+0

就这么简单。我有那个泛型树类,我有一个List对象,它们有自己的ID和老板的ID。我只想知道4.5下最干净的方法是什么。我知道我可以查找如何填充一棵树,但有一些非常差的例子,只是寻找输入。我已经在这里看到了一些惊人的魔力,特别是像LINQ这样的事情,这些都极大地简化了我的代码。 – Patrick

回答

2

因此,考虑到你有定义为这样的Person类:

public class Person 
{ 
    public int ID; 
    public int? BossID; 
} 

...和你有一个List<Person>定义为people那么这个工程:

var lookup = people.ToLookup(p => p.BossID); 

Action<TreeNode<Person>> addChildren = null; 
addChildren = p => 
{ 
    foreach (var child in lookup[p.Item.ID]) 
    { 
     var childNode = p.AddChild(child); 
     addChildren(childNode); 
    } 
}; 

var trees = 
    from boss in lookup[null] 
    select new TreeNode<Person>(boss); 

foreach (var tree in trees) 
{ 
    addChildren(tree); 
} 

这是假设你可能有一个以上的老板与null。如果你不那么好,只需运行这个代码并执行trees.First()

我用的TreeNode<T>的定义是这样的:

public class TreeNode<T> 
{ 
    private List<TreeNode<T>> Children; 

    public T Item { get; set; } 

    public TreeNode(T item) 
    { 
     this.Item = item; 
     this.Children = new List<TreeNode<T>>(); 
    } 

    public TreeNode<T> AddChild(T item) 
    { 
     var nodeItem = new TreeNode<T>(item); 
     this.Children.Add(nodeItem); 
     return nodeItem; 
    } 
} 

你可以缩短TreeNode<T>这虽然:

public class TreeNode<T> : List<TreeNode<T>> 
{ 
    public T Item { get; set; } 

    public TreeNode(T item) 
    { 
     this.Item = item; 
    } 
} 

...那么你需要修改addChildren这样的:

Action<TreeNode<Person>> addChildren = null; 
addChildren = p => 
{ 
    foreach (var child in lookup[p.Item.ID]) 
    { 
     var childNode = new TreeNode<Person>(child); 
     p.Add(childNode); 
     addChildren(childNode); 
    } 
}; 

...但是你会拥有所有的标准rd List<>运营商可用于TreeNode<T>

+0

@Patrick - 如果你确定只有一个老板,那么做'var boss = trees.First();'。 – Enigmativity

+0

在这种情况下,只有一个老板应该存在Single/SingleOrDefault会更好,因为在此之后,您将知道是否存在数据错误,因为只允许一个老板 –

+0

@Enigmativity我正在使用您的代码接受新方法一个参数,所有的人('List people')。 'people.Count'等于25开头。它没有按预期工作。 'foreach(树中的var树)'这一行进入循环一次,调用'addChildren(tree);'where'tree.Count = 0'。我不确定问题是什么。 – Patrick