【问题标题】:Build a simple, high performance Tree Data Structure in c#用 c# 构建一个简单、高性能的树形数据结构
【发布时间】:2012-03-25 12:45:49
【问题描述】:

我需要创建一个树型的产品目录。

每个树节点都由一个ID(字符串)表示,树数据上的函数只有2个:

  1. getChild(string ID),给个ID,得到孩子(不需要包括孩子的) children),如果 ID 为 null,则获取所有根节点
  2. getParent(string ID),如果有则返回父ID,如果是root则返回null

由于树一旦决定,就不会改变,所以我认为将所有代码放在静态中会最好。 所以我开始尝试使用字典

"id": {parent:ID, child:[id2, id3, id4....]}

由于大约有 1000 多个目录,我发现我很快就搞砸了,静态数据中有很多错误,最终结果可用。还有,现在我只写了几十个,代码看起来乱七八糟。

请建议一种方法来创建这个高性能的简单目录树。谢谢

【问题讨论】:

  • 您的原始数据源是什么? XML?实体? json?
  • 原始数据是另一种完全不同的语言,所以我需要用 c# 编写,普通的硬编码 c# 代码对我来说很好,因为一旦完成,结构就不会改变。
  • "既然做完了,结构就不会变"....怀疑:D
  • @Jeroen,可能需要更改,然后我只需添加额外的代码,重新编译,重新部署。它不会每天都发生。
  • 稳健的树形结构经得起时间(和功能要求)的考验。

标签: c# tree


【解决方案1】:

只需用它制作一个类。

更新:

class TreeNode : IEnumerable<TreeNode>
{
    private readonly Dictionary<string, TreeNode> _children =
                                        new Dictionary<string, TreeNode>();

    public readonly string ID;
    public TreeNode Parent { get; private set; }

    public TreeNode(string id)
    {
        this.ID = id;
    }

    public TreeNode GetChild(string id)
    {
        return this._children[id];
    }

    public void Add(TreeNode item)
    {
        if (item.Parent != null)
        {
            item.Parent._children.Remove(item.ID);
        }

        item.Parent = this;
        this._children.Add(item.ID, item);
    }

    public IEnumerator<TreeNode> GetEnumerator()
    {
        return this._children.Values.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return this.GetEnumerator();
    }

    public int Count
    {
        get { return this._children.Count; }
    }
}

静态定义的用法相当简单:

var tree = new TreeNode("Root")
               {
                   new TreeNode("Category 1")
                       {
                           new TreeNode("Item 1"),
                           new TreeNode("Item 2"),
                           new TreeNode("Item 3"),
                       },
                   new TreeNode("Category 2")
                       {
                           new TreeNode("Item 1"),
                           new TreeNode("Item 2"),
                           new TreeNode("Item 3"),
                           new TreeNode("Item 4"),
                       }
               };

编辑

更多功能,更容易创建...

public static TreeNode BuildTree(string tree)
{
    var lines = tree.Split(new[] { Environment.NewLine },
                           StringSplitOptions.RemoveEmptyEntries);

    var result = new TreeNode("TreeRoot");
    var list = new List<TreeNode> { result };

    foreach (var line in lines)
    {
        var trimmedLine = line.Trim();
        var indent = line.Length - trimmedLine.Length;

        var child = new TreeNode(trimmedLine);
        list[indent].Add(child);

        if (indent + 1 < list.Count)
        {
            list[indent + 1] = child;
        }
        else
        {
            list.Add(child);
        }
    }

    return result;
}

public static string BuildString(TreeNode tree)
{
    var sb = new StringBuilder();

    BuildString(sb, tree, 0);

    return sb.ToString();
}

private static void BuildString(StringBuilder sb, TreeNode node, int depth)
{
    sb.AppendLine(node.ID.PadLeft(node.ID.Length + depth));

    foreach (var child in node)
    {
        BuildString(sb, child, depth + 1);
    }
}


用法:

var tree = TreeNode.BuildTree(@"
Cat1
 Sub1
  Item1
  Item2
  Item3
 Sub2
  Item1
  Item2
Cat2
 Sub1
 Sub2
  Item1
  Item2
 Sub3
  Item1
Cat3
Cat4");

【讨论】:

  • @EricYin 查看更新和编辑,还请注意,如果您愿意,可以将 Add 方法设为私有,方法是让静态 TreeNode ctor 构建静态树,或者您可以“发信号”将该树变为只读,因此 Add 方法将过时或引发只读异常。
  • @YoryeNathan:+1 干得好。您可能会考虑使用AttachTo(TreeNode parent) 方法来设置父级,并相应地设置父级的子级。也可能是Detach() 方法。
  • getChild 方法是一个实例方法。它返回具有指定名称的树节点的子节点。例如,要获取 Cat2 的所有子代,您应该将 Cat2 的实例作为 IEnumerator。关于根 - 您应该保留对根的静态引用,因为 ot 是所有其他节点的入口点。要查找具有特定 id 的节点,而不是节点的直接子节点,您应该使用基于静态递归的方法,使用根作为搜索起点,或者还保留一个静态字典以包含所有节点。
  • 没关系!我在这里找到了解决方案:code.google.com/p/yet-another-tree-structure/wiki/CSharpTree
  • 使用 Net Core 我需要将 IEnumerator IEnumerable 返回到 IEnumerator 类型。
【解决方案2】:

我创建了一个Node class,这可能会有所帮助。它速度很快并且有一些额外的属性,比如:

  • 祖先
  • 后裔
  • 兄弟姐妹
  • 节点级别
  • 父母

【讨论】:

    【解决方案3】:

    你可以写一个简单的二叉树,我在下面写了一些伪代码:

    class TreeNode {
        TreeNode Right;
        TreeNode Left;
        int id;
        //...
    }
    
    class BinTree {
    
        void Insert(TreeNode node)
        {
            while(true) {   
                if(node.id > target.id) {
                    if(target.Right != null) {
                        target = target.Right;
                        continue;
                    }
                    else {
                        target.Right = node;
                        break;
                    }
                }
    
                else if(node.id < target.id) {
                    if(target.Left != null) {
                        target = target.Left;
                        continue;
                    }
                    else {
                        target.Left = node;
                        break;
                    }   
                }
    
                else {
                    throw new ArgumentException("Duplicated id");
                }
            }
        }
    
    
        TreeNode Search(int id)
        {
            TreeNode target = root;
    
            while(target != null) {
                if(id > target.id) {
                    target = target.Right;
                }
                else if(id < target.id) {
                    target = target.Left;
                }
                else {
                    return target;
                }
            }
    
            return null;
        }
    
    }
    

    但如果你的数据量很大,也许 AVL 树更高效

    【讨论】:

    • -1 根本不满足他的需要。他想要一棵树作为产品目录。二叉树远不是他所需要的,即使在那之后,他也不需要它平衡或排序,因为目录有一个逻辑结构要维护。
    • +1:不是我想的那样,但是 OP 并没有优先考虑树结构的类型。
    • @YoryeNathan:我不同意。除了 2 个要求外,OP 没有给出偏好:simpleperformance。这个答案提供了两者。那些不了解树在做什么的人可能会失去简单性,但它肯定比线性(或不平衡)树更有效。
    • @IAbstract 一件事是阅读这个人的要求,另一件事是了解他的需求。他需要表示一个目录,它没有任何二叉树属性/约束。
    • @YoryeNathan:我理解 OP 的要求,我最初的想法与您提出的结构相同。这个答案很有价值,可以实施以满足 OP 的需求。如果性能将成为一个问题,那么这是两个选项中更好的一个。如果更喜欢简单,那么标准不平衡树是两个选项中更好的选择。
    猜你喜欢
    • 1970-01-01
    • 2019-04-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-18
    • 1970-01-01
    • 2013-05-17
    • 1970-01-01
    相关资源
    最近更新 更多