在写程序时,经常要用到树的这种结构,如果是做界面编程,那么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);
//
建立树型结构