我在C#中寻找树或图形数据结构,但我想没有提供.对数据结构的广泛检查使用C#2.0解释了一些原因.是否有一个方便的库,通常用于提供此功能?也许通过策略模式来解决文章中提出的问题.
我觉得实现自己的树有点傻,就像我实现自己的ArrayList一样.
我只想要一个可以不平衡的通用树.想一下目录树.C5看起来很漂亮,但它们的树结构似乎被实现为更适合搜索的平衡红黑树而不是表示节点的层次结构.
我最好的建议是没有标准的树数据结构,因为有很多方法可以实现它,用一个解决方案覆盖所有基础是不可能的.解决方案越具体,它就越不可能适用于任何给定的问题.我甚至对LinkedList感到恼火 - 如果我想要一个循环链表怎么办?
您需要实现的基本结构将是一组节点,这里有一些选项可以帮助您入门.我们假设类Node是整个解决方案的基类.
如果只需要向下导航树,那么Node类需要一个子列表.
如果需要向上导航树,则Node类需要指向其父节点的链接.
构建一个AddChild方法,负责处理这两点的所有细节以及必须实现的任何其他业务逻辑(子限制,对子项进行排序等)
delegate void TreeVisitor(T nodeData); class NTree { private T data; private LinkedList > children; public NTree(T data) { this.data = data; children = new LinkedList >(); } public void AddChild(T data) { children.AddFirst(new NTree (data)); } public NTree GetChild(int i) { foreach (NTree n in children) if (--i == 0) return n; return null; } public void Traverse(NTree node, TreeVisitor visitor) { visitor(node.data); foreach (NTree kid in node.children) Traverse(kid, visitor); } }
简单的递归实现...... <40行代码...你只需要保持对类外部树的根的引用,或者将它包装在另一个类中,也许重命名为TreeNode?
在我看来,这是我的,与Aaron Gage非常相似,只是更传统一点.出于我的目的,我没有遇到任何性能问题List
.如果需要,可以很容易地切换到LinkedList.
namespace Overby.Collections { public class TreeNode{ private readonly T _value; private readonly List > _children = new List >(); public TreeNode(T value) { _value = value; } public TreeNode this[int i] { get { return _children[i]; } } public TreeNode Parent { get; private set; } public T Value { get { return _value; } } public ReadOnlyCollection > Children { get { return _children.AsReadOnly(); } } public TreeNode AddChild(T value) { var node = new TreeNode (value) {Parent = this}; _children.Add(node); return node; } public TreeNode [] AddChildren(params T[] values) { return values.Select(AddChild).ToArray(); } public bool RemoveChild(TreeNode node) { return _children.Remove(node); } public void Traverse(Action action) { action(Value); foreach (var child in _children) child.Traverse(action); } public IEnumerable Flatten() { return new[] {Value}.Concat(_children.SelectMany(x => x.Flatten())); } } }
另一种树形结构:
public class TreeNode: IEnumerable > { public T Data { get; set; } public TreeNode Parent { get; set; } public ICollection > Children { get; set; } public TreeNode(T data) { this.Data = data; this.Children = new LinkedList >(); } public TreeNode AddChild(T child) { TreeNode childNode = new TreeNode (child) { Parent = this }; this.Children.Add(childNode); return childNode; } ... // for iterator details see below link }
样品用法:
TreeNoderoot = new TreeNode ("root"); { TreeNode node0 = root.AddChild("node0"); TreeNode node1 = root.AddChild("node1"); TreeNode node2 = root.AddChild("node2"); { TreeNode node20 = node2.AddChild(null); TreeNode node21 = node2.AddChild("node21"); { TreeNode node210 = node21.AddChild("node210"); TreeNode node211 = node21.AddChild("node211"); } } TreeNode node3 = root.AddChild("node3"); { TreeNode node30 = node3.AddChild("node30"); } }
奖金
见完全成熟的树:
迭代器
搜索
的Java/C#
https://github.com/gt4dev/yet-another-tree-structure
通常优秀的C5通用集合库有几种不同的基于树的数据结构,包括集合,包和字典.如果您想研究其实现细节,可以使用源代码.(我在生产代码中使用了C5集合,但是我没有特别使用任何树结构.)
见http://quickgraph.codeplex.com/
QuickGraph为.Net 2.0及更高版本提供通用的定向/无向图形数据结构和算法.QuickGraph带有深度优先搜索,呼吸优先搜索,A*搜索,最短路径,k最短路径,最大流量,最小生成树,最少共同祖先等算法... QuickGraph支持MSAGL,GLEE和Graphviz渲染图形,序列化为GraphML等...
如果您想自己编写,可以从这个由六部分组成的文档开始,详细介绍C#2.0数据结构的有效使用以及如何分析C#中数据结构的实现.每篇文章都有示例和安装程序,其中包含您可以使用的示例.
Scott Mitchell撰写的"使用C#2.0对数据结构进行了广泛的检查"
我对解决方案有一点延伸.
使用递归泛型声明和派生子类,您可以更好地专注于您的实际目标.
请注意,它与非泛型实现不同,您不需要在'NodeWorker'中强制转换'node'.
这是我的例子:
public class GenericTreewhere T : GenericTree // recursive constraint { // no specific data declaration protected List children; public GenericTree() { this.children = new List (); } public virtual void AddChild(T newChild) { this.children.Add(newChild); } public void Traverse(Action visitor) { this.traverse(0, visitor); } protected virtual void traverse(int depth, Action visitor) { visitor(depth, (T)this); foreach (T child in this.children) child.traverse(depth + 1, visitor); } } public class GenericTreeNext : GenericTree // concrete derivation { public string Name {get; set;} // user-data example public GenericTreeNext(string name) { this.Name = name; } } static void Main(string[] args) { GenericTreeNext tree = new GenericTreeNext("Main-Harry"); tree.AddChild(new GenericTreeNext("Main-Sub-Willy")); GenericTreeNext inter = new GenericTreeNext("Main-Inter-Willy"); inter.AddChild(new GenericTreeNext("Inter-Sub-Tom")); inter.AddChild(new GenericTreeNext("Inter-Sub-Magda")); tree.AddChild(inter); tree.AddChild(new GenericTreeNext("Main-Sub-Chantal")); tree.Traverse(NodeWorker); } static void NodeWorker(int depth, GenericTreeNext node) { // a little one-line string-concatenation (n-times) Console.WriteLine("{0}{1}: {2}", String.Join(" ", new string[depth + 1]), depth, node.Name); }