在写程序时,经常要用到树的这种结构,如果是做界面编程,那么TreeView是一个不错的选择,几个设置就能把数据绑定好,但是如果自己写类呢?相对就麻烦一点。
这里讨论一下如何快速建立自己的树型结构,即怎么把建树的方法抽离出来加以复用。
代码的复用,不外乎类,接口,泛型。
先考虑用接口来实现,定义一个ITreeNode 然后每一个要建立树型结构的结点去实现?感觉不大好,因为你要定义比如Parent Children等一系列的东西,很是很麻烦,每一个实现起来也很困难。
那抽像类?抽象类的继承到是方便,但是在实际使用中涉及各种类型转换,代码写起来不爽。
泛型呢?泛型的结构又过于笼统 ,但是可以折衷一下,就是用泛型定义一个结点的类
(小弟写代码方式都相对“妥协”,一位大人说的,各位将就着看哈)
1 namespace Soway.DB.Tree 2 { 3 public class TreeNode<T> 4 { 5 6 public T Data { get; set; } 7 public TreeNode<T> Parent { get; set; } 8 public List<TreeNode<T>> Children { get; set; } 9 }10 }
结点类定义好了以后,就要去实现一个 TreeFactory ,将建树的通用算法提出来。
namespace Soway.DB.Tree{ public class TreeFactory <T> { public List<TreeNode<T>> CreateTreeByLevel (List<T> Items ) { ////// } }}
这里的我的方法名已经默认为ByLevel ,即按层建立树,这样,新的问题又出现了:
1.怎么保证输入值Items是已经按层遍立建立好的结点?
2.怎么分层?即怎么区分树的父结点,子结点,同级结点之间的关系 ?
这些问题其实都与泛型的具体类型有关,但如果把具体类型约束了,那就违反我们本意了。
走一步算一步,先这样,把树结点之间的关系定义出来,算是一个枚举吧:
namespace Soway.DB.Tree{ public enum TeeNodeCompareResult { /// <summary> /// 树结点 /// </summary> Parent, /// <summary> /// 子结点 /// </summary> Child, /// <summary> /// 下一个同级结点 /// </summary> NextNode, /// <summary> /// 前一个同级结点 /// </summary> PReNode, /// <summary> /// 同一个结点 /// </summary> EquealNode , /// <summary> /// 下一层的结点 /// </summary> NexLevelNode }}
有了这个关系以后,于是有了进一步的想法,考虑传递给TreeFactory一个委托,可以通过这个来得到两个结点之间比较关系:
namespace Soway.DB.Tree{ public delegate TeeNodeCompareResult TeeNodeCompare<T>(T child, T parent);}
这样,我们的TreeFactory里多了一个泛型委托的成员。。。
private TeeNodeCompare<T> compare; public TreeFactory(Tree.TeeNodeCompare<T> Compare) { this.compare = Compare; }
现在,当这个泛型委托处理好了以后,我们下一步问题也好办了,就是将输入的Items进行按层排序,这时,只要有一个Comparison<T>()的实现 ,我直接调用 List<T>.Sort(Comprarion<T>)即可了
下面给出这个Comparation<T>的实现 :
private int CompareResult(T ob1, T ob2) { switch (compare(ob1, ob2)) { case TeeNodeCompareResult.Child: case TeeNodeCompareResult.NextNode: case TeeNodeCompareResult.NexLevelNode: return 1; case TeeNodeCompareResult.Parent : case TeeNodeCompareResult.PreNode: return -1; default : return 0; } }
好,这些基础工作做完以后,建树的就容易了:
/// <summary> /// 按层建立树 /// </summary> /// <param name="Items">建立树的集合</param> /// <returns>建立好的树结构</returns> public List<TreeNode<T>> CreateTreeByLevel (List<T> Items ) { Items.Sort(new Comparison<T>(this.CompareResult)); List<TreeNode<T>> result = new List<TreeNode<T>>(); TreeNode<T> lastNode =null; Queue<TreeNode<T>> queue = new Queue<TreeNode<T>>(); TreeNode<T> currentNode=null; var current = result; if (Items.Count > 0) { for (int i = 0; i < Items.Count ; i++) { TreeNode<T> AddedNode = new TreeNode<T>(){Data=Items[i], Parent = null,Children = new List<TreeNode<T>>()};//生成要添加的数据 queue.Enqueue(AddedNode);//入队 //看是否到了下一层的结点 if (lastNode != null && (compare(AddedNode.Data, lastNode.Data) == Tree.TeeNodeCompareResult.Child || compare(AddedNode.Data, lastNode.Data) == Tree.TeeNodeCompareResult.NexLevelNode)//下一层:即结点是子结点或是下一层结点 ) { currentNode = queue.Dequeue(); } //找到对应的父结点 while (currentNode != null && compare(AddedNode.Data, currentNode.Data) != TeeNodeCompareResult.Child ) { currentNode = queue.Dequeue(); } if (currentNode !=null && compare(AddedNode.Data, currentNode.Data) != TeeNodeCompareResult.EquealNode) { AddedNode.Parent = currentNode; current = currentNode.Children; } current.Add(AddedNode); lastNode = AddedNode; } } return result; }
下面是一个使用的Demo ^_^
//类:{ [Table(Name="Auth")] public class Auth { [Column(IsKey=true)] public string Code { get; set; } public string Name { get; set; } public String Url { get; set; } public string View { get; set; } public string Action { get; set; } public string Text { get; set; } public string Image { get; set; } public override string ToString() { return Code + " " + Name; } }//比较结点的关系: static Soway.DB.Tree.TeeNodeCompareResult compare(Auth ob1, Auth ob2) { if (ob1.Code == ob2.Code) return TeeNodeCompareResult.EquealNode; if (ob1.Code.Length > ob2.Code.Length) if (ob1.Code.IndexOf(ob2.Code) == 0) return TeeNodeCompareResult.Child; else return TeeNodeCompareResult.NexLevelNode; else if (ob1.Code.Length < ob2.Code.Length) return TeeNodeCompareResult.Parent; else if (ob1.Code.CompareTo(ob2.Code) < 0) return TeeNodeCompareResult.PreNode; else return TeeNodeCompareResult.NextNode; }///主函数中 var c = new Soway.DB.DBContext(builder.ToString()); var items = c.Get<Auth >();//初始化 var tree = new TreeFactory<Auth>(new TeeNodeCompare<Auth>(compare)).CreateTreeByLevel(items);//建立树型结构
新闻热点
疑难解答