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); // 建立树型结构

 

你可能感兴趣的:(C#)