C#中一種通用的樹的產生方式

來源:互聯網
上載者:User

在寫程式時,經常要用到樹的這種結構,如果是做介面編程,那麼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);//建立樹型結構

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.