C#構建樹形數據結構
阿新 • • 發佈:2018-07-12
foreach nodes bject diag json數據格式 int har esp 修改
轉自: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(); }
C#構建樹形數據結構