轉自:https://www.jb51.net/article/125747.htm
樹形結構:最近在做任務管理,任務可以無限派生子任務且沒有數量限制,前端采用Easyui的Treegrid樹形展示控件。
a.JSON數據格式:
[
{
"children":[
{
"children":[
],
"username":"username2",
"password":"password2",
"id":"2",
"pId":"1",
"name":"節點2"
},
{
"children":[
],
"username":"username2",
"password":"password2",
"id":"A2",
"pId":"1",
"name":"節點2"
}
],
"username":"username1",
"password":"password1",
"id":"1",
"pId":"0",
"name":"節點1"
}
]
b.定義實體必要字段
為了Tree結構的通用性,我們可以定義一個抽象的公用實體TreeObject以保證后續涉及到的List<T>轉化樹形JSON
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MyTree.Abs
{
public class TreeObejct
{
public string id { set; get; }
public string pId { set; get; }
public string name { set; get; }
public IList<TreeObejct> children = new List<TreeObejct>();
public virtual void Addchildren(TreeObejct node)
{
this.children.Add(node);
}
}
}
c.實際所需實體TreeModel讓它繼承TreeObject,這樣對於id,pId,name,children我們就可以適用於其它實體了,這也相當於我們代碼的特殊約定:
using MyTree.Abs;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MyTree.Models
{
public class TreeModel : TreeObejct
{
public string username { set; get; }
public string password { set; get; }
}
}
2、遞歸遍歷
獲取全部任務並轉化為樹形
獲取全部任務轉化為樹形是比較簡單的,我們首先獲取到pId=0的頂級數據(即不存在父級的任務),我們通過頂級任務依次遞歸遍歷它們的子節點。
/ //遞歸獲取所有樹結構的數據
public IList<TreeObject> GetData()
{
List<TreeObject> nodes = _context.Node.Where(x => x.parent_node_id == 0).Select(x=>new TreeObject { id=x.id,pId=x.parent_node_id,name=x.name}).ToList();
foreach(TreeObject item in nodes)
{
item.children = GetChildrens(item);
}
return nodes;
}
//遞歸獲取子節點
public IList<TreeObject> GetChildrens(TreeObject node)
{
IList<TreeObject> childrens = _context.Node.Where(c => c.parent_node_id == node.id).Select(x => new TreeObject { id = x.id, pId = x.parent_node_id, name = x.name }).ToList();
foreach (TreeObject item in childrens)
{
item.children = GetChildrens(item);
}
return childrens;
}
3、非遞歸遍歷
非遞歸遍歷在操作中不需要遞歸方法的參與即可實現Tree的拼接
對於以上的代碼,我們不需要修改,只需要定義一個非遞歸遍歷方法NotRecursion:
public static void NotRecursion()
{
#region 非遞歸遍歷
System.Diagnostics.Stopwatch sw2 = new System.Diagnostics.Stopwatch();
sw2.Start();
Dictionary<string, TreeObejct> dtoMap = new Dictionary<string, TreeObejct>();
foreach (var item in models)
{
dtoMap.Add(item.id, item);
}
IList<TreeObejct> result = new List<TreeObejct>();
foreach (var item in dtoMap.Values)
{
if (item.pId == "0")
{
result.Add(item);
}
else
{
if (dtoMap.ContainsKey(item.pId))
{
dtoMap[item.pId].AddChilrden(item);
}
}
}
sw2.Stop();
Console.WriteLine("----------非遞歸遍歷用時:" + sw2.ElapsedMilliseconds + "----------線程名稱:" + t2.Name + ",線程ID:" + t2.ManagedThreadId);
#endregion
main.cs
private static IList<TreeObejct> models;
private static IList<TreeObejct> models2;
private static Thread t1;
private static Thread t2;
static void Main(string[] args)
{
int count = 6;
Console.WriteLine("生成任務數:"+count+"個");
models = GetData(count);
models2 = GetData(count);
t1 = new Thread(Recursion);
t2 = new Thread(NotRecursion);
t1.Name = "遞歸遍歷";
t2.Name = "非遞歸遍歷";
t1.Start();
t2.Start();
Console.Read();
}
