树在图论中是一种重要的图,由于其自身的许多特殊性质,也是一种重要的计算机数据结构,在很多地方都有用。但是这些树大多都是作为其他应用的内部数据结构来使用。我们无法了解这些树的详细信息,而 .Net 也没有在内置的集合类库中提供树形数据结构的类。很多时候我们都需要树形数据完成一些工作,在自己的实践经验和查阅大量相关资料后,我编写了一个使用简单,能方便地将普通集合转换为树形集合(当然前提是这些集合元素之间存在能够表明层级关系的数据),提供了大量图论中有关节点和整棵树的信息和常用算法的通用树形数据结构类。希望能够简化此类需求的开发。
正文图论中有关树的定义和性质都能很容易查到资料,就不再啰嗦,进入正题。首先,定义一个树形结构有很多方法,在此我选用最直观的双亲孩子表示法定义。为了能将包含层级信息的普通数据转换为树形数据,使用接口进行定义,并以接口为核心进行扩展。接口定义如下:
1 /// <summary> 2 /// 可分层数据接口 3 /// </summary> 4 /// <typeparam>数据类型</typeparam> 5 public interface IHierarchical<out T> 6 { 7 /// <summary> 8 /// 当前节点的数据 9 /// </summary> 10 T Current { get; } 11 12 /// <summary> 13 /// 根节点 14 /// </summary> 15 IHierarchical<T> Root { get; } 16 17 /// <summary> 18 /// 双亲(父)节点 19 /// </summary> 20 IHierarchical<T> Parent { get; } 21 22 /// <summary> 23 /// 祖先节点集合(按路径距离升序) 24 /// </summary> 25 IEnumerable<IHierarchical<T>> Ancestors { get; } 26 27 /// <summary> 28 /// 子节点集合 29 /// </summary> 30 IEnumerable<IHierarchical<T>> Children { get; } 31 32 /// <summary> 33 /// 后代节点集合(深度优先先序遍历) 34 /// </summary> 35 IEnumerable<IHierarchical<T>> Descendants { get; } 36 37 /// <summary> 38 /// 兄弟节点集合(不包括自身节点) 39 /// </summary> 40 IEnumerable<IHierarchical<T>> Siblings { get; } 41 42 /// <summary> 43 /// 在兄弟节点中的排行 44 /// </summary> 45 int IndexOfSiblings { get; } 46 47 /// <summary> 48 /// 节点的层 49 /// </summary> 50 int Level { get; } 51 52 /// <summary> 53 /// 节点(以当前节点为根的子树)的高度 54 /// </summary> 55 int Height { get; } 56 57 /// <summary> 58 /// 节点的度 59 /// </summary> 60 int Degree { get; } 61 62 /// <summary> 63 /// 树(以当前节点为根的子树)的所有节点中度最大的节点的度 64 /// </summary> 65 int MaxDegreeOfTree { get; } 66 67 /// <summary> 68 /// 当前节点是否是根节点 69 /// </summary> 70 bool IsRoot { get; } 71 72 /// <summary> 73 /// 当前节点是否是叶子节点 74 /// </summary> 75 bool IsLeaf { get; } 76 77 /// <summary> 78 /// 当前节点是否有子节点 79 /// </summary> 80 bool HasChild { get; } 81 82 /// <summary> 83 /// 以当前节点为根返回树形排版的结构字符串 84 /// </summary> 85 /// <param>数据对象格式化器(内容要为一行,否则会影响排版)</param> 86 /// <param>处理掉换行符变成单行文本</param> 87 /// <returns></returns> 88 string ToString(Func<T, string> formatter, bool convertToSingleLine = false); 89 }