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);//建立樹型結構



轉載自:http://www.cnblogs.com/geyunfei/archive/2011/12/08/2280626.html
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章