递归树创建

时间:2012-07-06 15:00:03

标签: c# recursion

我在C#中有一个Node类,具有以下属性:

public class Node
{
   public int Id {get;set;}
   public int? ParentId {get;set;}
   public string Label {get;set;}
}

我有一个TreeView控件,它提供了以下创建方法 一个新节点:

MyTreeView.CreateNode(key, label);
parent.Nodes.CreateNode(key, label);

如果我想添加一个新的子节点,我需要使用第二种方法,否则使用第一种方法。两者都返回TreeNode类型的对象。

考虑到根节点有ParentId = null,你将如何在C#中创建一个递归函数来填充树视图?

这是我到目前为止所做的:

// create a list of root nodes
var roots = myList.Where(x => x.ParentId == null);
// send the roots to a recursive func
foreach(var root in roots)
{
   AddNode(null,root,myList);
}

这是我的递归函数:

private void AddNode(Node parent, Node current, IList<Node> items)
{
   TreeNode treenode = null;
   if(parent == null)
   {
      treenode = mytree.CreateNode(current.Id.ToString(), current.Label);
   }else{
      var parentnode = mytree.GetNode(parent.Id.ToString());
      treenode = parentnode.Nodes.CreateNode(current.Id.ToString(), current.Label);
   }
   // call the recursion for the children
   var children = items.Where(x => x.ParentId == current.Id);
   foreach(var child in children)
   {
      AddNode(current, child, items);
   }
}

4 个答案:

答案 0 :(得分:0)

如果您的树视图控件是从System.Windows.Forms.TreeView派生的,则可以替换

MyTreeView.CreateNode(key, label);
parent.Nodes.CreateNode(key, label);

MyTreeView.Nodes.Add(key, label);
parent.Nodes.Add(key, label);

因此,调用始终转到TreeNodeCollection类型的Nodes集合。您现在可以使用节点集合作为参数来代替您的Node对象。

var roots = myList.Where(x => x.ParentId == null);
foreach (var root in roots)
{
    AddNode(mytree.Nodes, root, myList);
}

private void AddNode(TreeNodeCollection nodes, Node current, IList<Node> items)
{
    TreeNode treenode = nodes.Add(current.Id.ToString(), current.Label);

    var children = items.Where(x => x.ParentId == current.Id);
    foreach (var child in children)
    {
        AddNode(treenode.Nodes, child, items);
    }
}

这有两个好处:

  1. 您不需要每次都查找父级。
  2. 您只有一个电话(TreeNodeCollection.Add)。
  3. 但是,如果您无法在每个根的AddNode调用中访问TreeView.Nodes集合,则必须在AddNode方法的顶部检查它。

    var roots = myList.Where(x => x.ParentId == null);
    foreach (var root in roots)
    {
        AddNode(null, root, myList);
    }
    
    private void AddNode(TreeNodeCollection nodes, Node current, IList<Node> items)
    {
        if (nodes == null)
        {
            nodes = myTree.Nodes;
        }
    
        ...
    }
    

答案 1 :(得分:0)

试试这段代码:

var lookup = myList.ToLookup(n => n.ParentId.ToString());

Action<IEnumerable<TreeNode>> addChildren = null;
addChildren = tns =>
{
    var query =
        from tn in tns
        from cn in lookup[tn.Name]
        select tn.Nodes.CreateNode(cn.Id.ToString(), cn.Label);
    var nodes = query.ToArray();
    if (nodes.Length > 0)
    {
        addChildren(nodes);
    }
};

addChildren(
    lookup[null]
        .Select(n =>
            MyTreeView.CreateNode(n.Id.ToString(), n.Label)));

我无法完全测试它,因此您可能需要更改一些代码才能使其正常工作,但它应该非常接近。

答案 2 :(得分:0)

我可能会做这样的事情......

public class Node
{
    public int Id { get; set; }
    public int? ParentId { get; set; }
    public string Label { get; set; }

    public Node(int? parentId, int id, string label)
    {
        ParentId = parentId;
        Id = id;
        Label = label;
    }
}

public class TreeNode : List<TreeNode>
{
    public string Key { get; set; }
    public string Label { get; set; }


    public IEnumerable<TreeNode> Descendants
    {
        get
        {
            yield return this;

            foreach (var child in this)
            {
                foreach (var descendant in child.Descendants)
                {
                    yield return descendant;
                }

            }
        }
    }

    public TreeNode(string key, string label)
    {
        Key = key;
        Label = label;
    }

    public void CreateNode(int id, string label)
    {
        Add(new TreeNode(id.ToString(), label));
    }
}

public class Tree
{
    private TreeNode _root = new TreeNode(null, null);

    public Tree(IEnumerable<Node> nodes)
    {
        nodes.ToList().ForEach(node => CreateNode(node.ParentId, node.Id, node.Label));
    }

    public void CreateNode(int? parentId, int id, string label)
    {
        if (parentId == null)
        {
            _root.CreateNode(id, label);
        }
        else
        {
            _root.Descendants.First(x => x.Key == parentId.ToString()).CreateNode(id, label);
        }
    }

    public IEnumerable<TreeNode> Descendants => _root.Descendants;
}

答案 3 :(得分:-1)

试试这个代码:

Node{
     Id, Label, List<Tree> Children
}

Tree GetTree(id){
     var node=new Node();
     
     node.Id=id;
     node.Children=new List<Node>();
     
     List<Node> children = db.Nodes.Where(x => x.ParentId==id);
     
     foreach(child in children){
           var childTree=GetTree(child.Id);
           node.Children.Add(childTree);
     }
     
     return node;
}