构建树形结构数据(全部构建,查找构建)C#版
摘要:
最近在做任务管理,任务可以无限派生子任务且没有数量限制,前端采用Easyui的Treegrid树形展示控件。
一、遇到的问题
获取全部任务拼接树形速度过慢(数据量大约在900条左右)且查询速度也并不快;
二、解决方法
1、Tree转化的JSON数据格式
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"},{"children":[],"username":"username1","password":"password1","id":"A1","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 abstract 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的顶级数据(即不存在父级的任务),我们通过顶级任务依次递归遍历它们的子节点。
b.我们暂时id以1开始则pId=0的都为顶级任务
我们首先写一段生成数据的方法:
public static IList<TreeObejct> GetData(int number = 11){IList<TreeObejct> datas = new List<TreeObejct>();for (int i = 1; i < number; i++){datas.Add(new TreeModel{id = i.ToString(),pId = (i - 1).ToString(),name = "节点" + i,username = "username" + i,password = "password" + i});datas.Add(new TreeModel{id = "A" + i.ToString(),pId = (i - 1).ToString(),name = "节点" + i,username = "username" + i,password = "password" + i});}return datas;}
其次我们定义一些变量:
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 = 21;Console.WriteLine("生成任务数:"+count+"个");Console.Read();}
我们再写一个递归获取子节点的递归方法:
public static IList<TreeObejct> GetChildrens(TreeObejct node){IList<TreeObejct> childrens = models.Where(c => c.pId == node.id.ToString()).ToList();foreach (var item in childrens){item.children = GetChildrens(item);}return childrens;}
编写调用递归方法Recursion:
public static void Recursion(){#region 递归遍历System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();sw.Start();var mds_0 = models.Where(c => c.pId == "0");//获取顶级任务foreach (var item in mds_0){item.children = GetChildrens(item);}sw.Stop();Console.WriteLine("----------递归遍历用时:" + sw.ElapsedMilliseconds + "----------线程名称:"+t1.Name+",线程ID:"+t1.ManagedThreadId);#endregion}
编写main函数启动测试:
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 = 1001;Console.WriteLine("生成任务数:"+count+"个");models = GetData(count);t1 = new Thread(Recursion);t1.Name = "递归遍历";t1.Start();Console.Read();}
输出结果:
递归遍历至此结束。
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函数:
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();}
启动查看执行结果:
发现一个问题,递归3s,非递归0s,随后我又进行了更多的测试:
任务个数 | 递归(ms) | 非递归(ms) |
6 | 3 | 0 |
6 | 1 | 0 |
6 | 1 | 0 |
101 | 1 | 0 |
101 | 4 | 0 |
101 | 5 | 0 |
1001 | 196 | 5 |
1001 | 413 | 1 |
1001 | 233 | 7 |
5001 | 4667 | 5 |
5001 | 4645 | 28 |
5001 | 5055 | 7 |
10001 | StackOverflowException | 66 |
10001 | StackOverflowException | 81 |
10001 | StackOverflowException | 69 |
50001 | - | 46 |
50001 | - | 47 |
50001 | - | 42 |
100001 | - | 160 |
100001 | - | 133 |
100001 | - | 129 |
StackOverflowException:因包含的嵌套方法调用过多而导致执行堆栈溢出时引发的异常。 此类不能被继承。StackOverflowException 执行堆栈溢出发生错误时引发,通常发生非常深度或无限递归。
-:没有等到结果。
当然这个测试并不专业,但是也展示出了它的效率的确满足了当前的需求。
4、查找构建树形结果
原理同上述非递归相同,不同之处是我们通过查找的数据去构建树形
我们通过查找获取到圈中的任务,再通过当前节点获取到父级节点,因为当时没考虑到任务层级的关系,因此为添加层级编号,为此可能会有重复的存在,因此我们使用HashSet<T>来剔除我们的重复数据,最终获取到有用数据再通过非递归遍历方法,我们便可以再次构建出树形(tree),来转化为JSON数据。
参考文档:快速构建树形结构数据(非递归)
转载于:https://www.cnblogs.com/umeall/p/7660351.html
构建树形结构数据(全部构建,查找构建)C#版相关推荐
- Js 树形结构数据 根据ID 查找符合的一项
问:树的每一个节点包含了 id 和 label 字段,实现一个函数,输入关键字 searchKey,用于树节点 id 的匹配,查找 searchKey 对应树节点的数据,如果查找不到则返回 null ...
- Java后端递归构建树形结构
记录:在Java后台利用递归思路进行构建树形结构数据,返回给前端,能以下拉菜单等形式进行展示. 简明:为了简化代码,引入Lombok的Jar包,可省略实体类set().get()方法. <dep ...
- java构建树形结构
目录 前言 实现树形结构 一.树节点数据类(反回参数类) 二.给树形结构添加数据 三.测试类 四.测试结果 前言 在我们实际开发中会接触到树形结构,根节点子节点, 然后添加数据构成了我们的树形结构, ...
- oracle树状结构递归,Oracle:递归查询(树形结构数据)
Oracle树形结构数据-相关知识总结 Oracle树形结构数据--基本知识 1.数据组成 2.基本查询 2.1.查询某节点及该节点下的所有子孙节点 SELECT * FROM QIAN ...
- java构建树形菜单(多级菜单)
一.树形结构简介 首先构建树形结构,我们得知道什么是树形结构,如下图所示. 如上图所示,可以看出有四级菜单,这就是树形结构. 如果想更深入的了解树形结构,建议去查询数据结构中关于树的章节. 二.树形菜 ...
- java树形菜单_Java构建树形菜单
构建树形菜单 效果图:支持多级菜单. 菜单实体类: public class Menu { // 菜单id private String id; // 菜单名称 private String name ...
- java递归实现多级菜单栏_Java构建树形菜单以及支持多级菜单的实例代码
这篇文章主要介绍了Java构建树形菜单的实例代码(支持多级菜单),非常不错,具有参考借鉴价值,需要的朋友可以参考下 效果图:支持多级菜单. 菜单实体类: public class Menu { // ...
- C++ Qt 构建树形结构 树形结构生成XML
树形数据结构是一类重要的非线性数据结构.树形数据结构可以表示数据表素之间一对多的关系.其中以树与二叉树最为常用,直观看来,树是以分支关系定义的层次结构.树形数据结构在客观世界中广泛存在,如人类社会的族 ...
- docker容器构建_我如何容器化构建系统
docker容器构建 构建系统由用于从源代码过渡到正在运行的应用程序的工具和过程组成. 这种过渡还涉及将代码的读者从软件开发人员更改为最终用户,无论最终用户是运营方面的同事还是部署系统的同事. 在使用 ...
最新文章
- python 打印皮卡丘_Python到底是什么?学姐靠它拿了5个offer
- 淡水:21世纪的分子微生物生态学
- 《编写高质量Python代码的59个有效方法》——第10条:尽量用enumerate取代range
- PCA与LDA算法的解释,浅显易懂
- 【哈希和哈希表】Beads
- 《VMware vCAT权威指南:成功构建云环境的核心技术和方法》一3.8 多站点考虑因素...
- adb 常用命令集合
- redis设置key的有效期
- 在ASP.NET使用javascript的一点小技巧(转www.chinacs.net 中文C#技术站 )
- 透露一个未来3到5年的巨大商机
- [Ubuntu] zsh
- 在win10环境中安装xilinx vivado IDE时出现的问题及解决方法
- Machine Learning——Homework4
- Wacom 驱动安装 或者 失败重装
- 到底什么是模型预测控制MPC(一)
- 空洞卷积(Dilated Convolution)简介
- C++ MFC与三菱PLC通讯
- 今天终于把荣耀6root了_附教程
- 如何将微信公众号上的文章下载下来?
- 我的世界java版gamemode指令_我的世界(电脑Java版)简单又好玩指令教程
热门文章
- 大数据WEB阶段Spring框架(一)IOC控制反转、DI注入依赖
- 【机器视觉】 dev_map_var算子
- 【STM32】系统控制寄存器
- 【Linux】一步一步学Linux——ifdown命令(153)
- 通过命令解锁Oracle,在命令行下进行Oracle用户解锁
- java secretkey_Java中的SecretKeyFactory类 | 学步园
- 文字转wav_这6款超良心语音转文字工具,真让人省心!
- python iocp_记对协程增加IOCP支持时候踩过的一些坑
- Docker安装redis 设置密码
- Android在 普通类(非Activity,多数为Adapter) 中 传输数据为空值 解决方法 :在startActivity 用 intent传输数据