递归树的创建

5

我在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的对象。

如果要在C#中创建一个递归函数来填充树视图,考虑到根节点具有ParentId = null,该怎么做呢?

目前我已经完成了以下工作:

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

你需要添加C#标签。如果这是作业,你也应该添加作业标签。此外,你应该向我们展示你尝试过的代码示例。 - JamieSee
好的,我会修改帖子,谢谢。 - Raffaeu
1
这个函数有什么问题?除了你不需要变量treenode之外。 - Osama Javed
这是错误的,因为我必须在一个调用中完成所有操作,而我在这里做的是两个调用。我考虑使用LinQ添加扩展,但我不太擅长它。 - Raffaeu
1
你忘了提到一些我认为非常重要的事情。你正在基于某种IList生成你的树。你的列表中有什么?人们可以推断,但不能确定。 - Sam I am says Reinstate Monica
什么是2个调用?根据递归函数的定义,您至少需要2个调用:一个用于第一次迭代,另一个用于递归。而且,即使您的函数远非最佳,但它似乎是正确的。 - Samy Arous
4个回答

2
如果您的树形视图控件是从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集合。您现在可以使用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)。

但是,如果您在为每个根节点进行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;
    }

    ...
}

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

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

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


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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接