1. 程式人生 > >C#構建樹形數據結構

C#構建樹形數據結構

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#構建樹形數據結構