首页 > 学院 > 开发设计 > 正文

C#中一种通用的树的生成方式

2019-11-06 06:16:46
字体:
来源:转载
供稿:网友

在写程序时,经常要用到树的这种结构,如果是做界面编程,那么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);//建立树型结构
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表