zoukankan      html  css  js  c++  java
  • C#中一种通用的树的生成方式

    在写程序时,经常要用到树的这种结构,如果是做界面编程,那么TreeView是一个不错的选择,几个设置就能把数据绑定好,但是如果自己写类呢?相对就麻烦一点。

    这里讨论一下如何快速建立自己的树型结构,即怎么把建树的方法抽离出来加以复用。

    代码的复用,不外乎类,接口,泛型。

    先考虑用接口来实现,定义一个ITreeNode 然后每一个要建立树型结构的结点去实现?感觉不大好,因为你要定义比如Parent Children等一系列的东西,很是很麻烦,每一个实现起来也很困难。

    那抽像类?抽象类的继承到是方便,但是在实际使用中涉及各种类型转换,代码写起来不爽。

    泛型呢?泛型的结构又过于笼统 ,但是可以折衷一下,就是用泛型定义一个结点的类

    (小弟写代码方式都相对“妥协”,一位大人说的,各位将就着看哈)

     1 namespace Soway.DB.Tree
     2 {
     3     public class  TreeNode<T>
     4     {
     5 
     6         public T Data { getset; }
     7         public TreeNode<T> Parent { getset; }
     8         public List<TreeNode<T>> Children { getset; }
     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 { getset; }
            public string Name { getset; }
            public String Url { getset; }
            public string View { getset; }
            public string Action { getset; }
            public string Text { getset; }
            public string Image { getset; }


            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);//建立树型结构
  • 相关阅读:
    BZOJ2337 [HNOI2011]XOR和路径
    「学习笔记」3.31代码学习
    uva live 12846 A Daisy Puzzle Game
    Cannot use ImageField because Pillow is not installed
    Android点击Button水波纹效果
    hdu 1241 Oil Deposits
    c++ 字符输入读取
    clutter recoder
    C/C++获取数组长度
    vector array and normal stanard array
  • 原文地址:https://www.cnblogs.com/geyunfei/p/2280626.html
Copyright © 2011-2022 走看看