在寫程序時(shí),經(jīng)常要用到樹的這種結(jié)構(gòu),如果是做界面編程,那么TreeView是一個(gè)不錯(cuò)的選擇,幾個(gè)設(shè)置就能把數(shù)據(jù)綁定好,但是如果自己寫類呢?相對(duì)就麻煩一點(diǎn)。
這里討論一下如何快速建立自己的樹型結(jié)構(gòu),即怎么把建樹的方法抽離出來加以復(fù)用。
代碼的復(fù)用,不外乎類,接口,泛型。
先考慮用接口來實(shí)現(xiàn),定義一個(gè)ITreeNode 然后每一個(gè)要建立樹型結(jié)構(gòu)的結(jié)點(diǎn)去實(shí)現(xiàn)?感覺不大好,因?yàn)槟阋x比如Parent Children等一系列的東西,很是很麻煩,每一個(gè)實(shí)現(xiàn)起來也很困難。
那抽像類?抽象類的繼承到是方便,但是在實(shí)際使用中涉及各種類型轉(zhuǎn)換,代碼寫起來不爽。
泛型呢?泛型的結(jié)構(gòu)又過于笼統(tǒng) ,但是可以折衷一下,就是用泛型定義一個(gè)結(jié)點(diǎn)的類
(小弟寫代碼方式都相對(duì)“妥協(xié)”,一位大人說的,各位將就著看哈)
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 }
結(jié)點(diǎn)類定義好了以后,就要去實(shí)現(xiàn)一個(gè) TreeFactory ,將建樹的通用算法提出來。
namespace Soway.DB.Tree{ public class TreeFactory <T> { public List<TreeNode<T>> CreateTreeByLevel (List<T> Items ) { ////// } }}
這里的我的方法名已經(jīng)默認(rèn)為ByLevel ,即按層建立樹,這樣,新的問題又出現(xiàn)了:
1.怎么保證輸入值Items是已經(jīng)按層遍立建立好的結(jié)點(diǎn)?
2.怎么分層?即怎么區(qū)分樹的父結(jié)點(diǎn),子結(jié)點(diǎn),同級(jí)結(jié)點(diǎn)之間的關(guān)系 ?
這些問題其實(shí)都與泛型的具體類型有關(guān),但如果把具體類型約束了,那就違反我們本意了。
走一步算一步,先這樣,把樹結(jié)點(diǎn)之間的關(guān)系定義出來,算是一個(gè)枚舉吧:
namespace Soway.DB.Tree{ public enum TeeNodeCompareResult { /// <summary> /// 樹結(jié)點(diǎn) /// </summary> Parent, /// <summary> /// 子結(jié)點(diǎn) /// </summary> Child, /// <summary> /// 下一個(gè)同級(jí)結(jié)點(diǎn) /// </summary> NextNode, /// <summary> /// 前一個(gè)同級(jí)結(jié)點(diǎn) /// </summary> PReNode, /// <summary> /// 同一個(gè)結(jié)點(diǎn) /// </summary> EquealNode , /// <summary> /// 下一層的結(jié)點(diǎn) /// </summary> NexLevelNode }}
有了這個(gè)關(guān)系以后,于是有了進(jìn)一步的想法,考慮傳遞給TreeFactory一個(gè)委托,可以通過這個(gè)來得到兩個(gè)結(jié)點(diǎn)之間比較關(guān)系:
namespace Soway.DB.Tree{ public delegate TeeNodeCompareResult TeeNodeCompare<T>(T child, T parent);}
這樣,我們的TreeFactory里多了一個(gè)泛型委托的成員。。。
private TeeNodeCompare<T> compare; public TreeFactory(Tree.TeeNodeCompare<T> Compare) { this.compare = Compare; }
現(xiàn)在,當(dāng)這個(gè)泛型委托處理好了以后,我們下一步問題也好辦了,就是將輸入的Items進(jìn)行按層排序,這時(shí),只要有一個(gè)Comparison<T>()的實(shí)現(xiàn) ,我直接調(diào)用 List<T>.Sort(Comprarion<T>)即可了
下面給出這個(gè)Comparation<T>的實(shí)現(xiàn) :
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; } }
好,這些基礎(chǔ)工作做完以后,建樹的就容易了:
/// <summary> /// 按層建立樹 /// </summary> /// <param name="Items">建立樹的集合</param> /// <returns>建立好的樹結(jié)構(gòu)</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>>()};//生成要添加的數(shù)據(jù) queue.Enqueue(AddedNode);//入隊(duì) //看是否到了下一層的結(jié)點(diǎn) if (lastNode != null && (compare(AddedNode.Data, lastNode.Data) == Tree.TeeNodeCompareResult.Child || compare(AddedNode.Data, lastNode.Data) == Tree.TeeNodeCompareResult.NexLevelNode)//下一層:即結(jié)點(diǎn)是子結(jié)點(diǎn)或是下一層結(jié)點(diǎn) ) { currentNode = queue.Dequeue(); } //找到對(duì)應(yīng)的父結(jié)點(diǎn) 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; }
下面是一個(gè)使用的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; } }//比較結(jié)點(diǎn)的關(guān)系: 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; }///主函數(shù)中 var c = new Soway.DB.DBContext(builder.ToString()); var items = c.Get<Auth >();//初始化 var tree = new TreeFactory<Auth>(new TeeNodeCompare<Auth>(compare)).CreateTreeByLevel(items);//建立樹型結(jié)構(gòu)新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注