在寫程序時,經常要用到樹的這種結構,如果是做界面編程,那麼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;
}
///主函數中 www.2cto.com
var c = new Soway.DB.DBContext(builder.ToString());
var items = c.Get<Auth >();//初始化
var tree = new TreeFactory<Auth>(new TeeNodeCompare<Auth>(compare)).CreateTreeByLevel(items);//建立樹型結構
摘自 葛雲飛