tnblog
首页
视频
资源
登录

tree 树形递归解析算法,处理特殊的根节点条件,特定的顶级顶层条件。树形获取顶级下面所有的子级id

808人阅读 2024/11/7 21:19 总访问:891593 评论:0 收藏:0 手机
分类: 后端

一般情况下的递归解析树形参考:
https://www.tnblog.net/aojiancc2/article/details/4785
这个是sqlsugar封装的关于树形相关的方法
https://www.donet5.com/home/doc?masterId=1&typeId=2311

树形递归解析算法,处理特殊的根节点条件,特定的顶级顶层条件

在sqlsguar中有一个这样的表

  1. public class Tree
  2. {
  3. [SqlSugar.SugarColumn(IsPrimaryKey = true)]
  4. public int Id { get; set; }
  5. public string Name { get; set; }
  6. public int ParentId { get; set; }
  7. public string Type { get; set; }
  8. public List<Tree> Child { get; set; }
  9. }

一般情况下顶级的都是ParentId=0或者是null,但是这里的情况有一点特殊,最顶层的数据是type=’校区’或者type = ‘一级部门’
应该怎么写递归算法处理这种结构的数据成一个树形结构呢。

最顶层的数据的 Type 属性值为 '校区''一级部门'。以下是实现这个功能的代码示例:

首先,假设你已经从数据库中获取了所有的 Tree 对象并存储在一个列表中,比如 List<Tree> allTrees

接下来,你可以使用以下递归算法来构建树形结构:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. public class Tree
  5. {
  6. [SqlSugar.SugarColumn(IsPrimaryKey = true)]
  7. public int Id { get; set; }
  8. public string Name { get; set; }
  9. public int ParentId { get; set; }
  10. public string Type { get; set; }
  11. public List<Tree> Child { get; set; } = new List<Tree>();
  12. }
  13. public class TreeBuilder
  14. {
  15. public List<Tree> BuildTree(List<Tree> allTrees)
  16. {
  17. // 查找根节点,即 Type 为 '校区' 或 '一级部门' 的节点
  18. var roots = allTrees.Where(t => t.Type == "校区" || t.Type == "一级部门").ToList();
  19. // 创建一个字典,方便根据 Id 快速查找节点
  20. var treeLookup = allTrees.ToDictionary(t => t.Id);
  21. // 递归函数,构建树形结构
  22. void BuildTreeRecursive(Tree parent)
  23. {
  24. foreach (var childId in allTrees
  25. .Where(t => t.ParentId == parent.Id)
  26. .Select(t => t.Id))
  27. {
  28. if (treeLookup.TryGetValue(childId, out var child))
  29. {
  30. parent.Child.Add(child);
  31. BuildTreeRecursive(child);
  32. }
  33. }
  34. }
  35. // 对每个根节点调用递归函数
  36. foreach (var root in roots)
  37. {
  38. BuildTreeRecursive(root);
  39. }
  40. return roots;
  41. }
  42. }
  43. // 示例用法
  44. public class Program
  45. {
  46. public static void Main()
  47. {
  48. // 假设这是从数据库中获取的所有 Tree 对象
  49. List<Tree> allTrees = new List<Tree>
  50. {
  51. // 示例数据
  52. new Tree { Id = 1, Name = "校区A", ParentId = 0, Type = "校区" },
  53. new Tree { Id = 2, Name = "部门1", ParentId = 1, Type = "一级部门" },
  54. new Tree { Id = 3, Name = "部门2", ParentId = 1, Type = "一级部门" },
  55. new Tree { Id = 4, Name = "小组1", ParentId = 2, Type = "小组" },
  56. new Tree { Id = 5, Name = "小组2", ParentId = 2, Type = "小组" },
  57. // 添加更多数据...
  58. };
  59. TreeBuilder builder = new TreeBuilder();
  60. List<Tree> treeStructure = builder.BuildTree(allTrees);
  61. // 输出或处理 treeStructure
  62. PrintTree(treeStructure, 0);
  63. }
  64. public static void PrintTree(List<Tree> trees, int indent)
  65. {
  66. foreach (var tree in trees)
  67. {
  68. Console.WriteLine($"{new string(' ', indent * 2)}{tree.Name} ({tree.Type})");
  69. PrintTree(tree.Child, indent + 1);
  70. }
  71. }
  72. }

代码解释

  1. Tree 类:包含树节点的定义,包括 Id, Name, ParentId, Type, 和 Child 列表。

  2. TreeBuilder 类:包含构建树形结构的 BuildTree 方法。

  3. BuildTree 方法

    • 首先,查找根节点,即 Type'校区''一级部门' 的节点。
    • 创建一个字典 treeLookup,用于根据 Id 快速查找节点。
    • 定义递归函数 BuildTreeRecursive,用于构建树形结构。
    • 对每个根节点调用递归函数。
  4. PrintTree 方法:用于打印树形结构,便于验证结果。

  5. 示例用法:创建一些示例数据,并调用 BuildTree 方法构建树形结构,最后打印出来。

通过这种方式,你可以将平面表数据转换为树形结构,并处理特定的根节点条件。

树形获取顶级下面所有的子级id

代码如下:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. public class Tree
  5. {
  6. public int Id { get; set; }
  7. public string Name { get; set; }
  8. public int? ParentId { get; set; }
  9. public string Type { get; set; }
  10. public List<Tree> Child { get; set; } = new List<Tree>();
  11. }
  12. public class TreeHelper
  13. {
  14. public Dictionary<int, List<int>> GetAllSubDepartmentIds(List<Tree> trees)
  15. {
  16. // 字典来存储每个顶级部门ID及其所有子部门ID
  17. Dictionary<int, List<int>> subDepartmentIdsByTopDepartment = new Dictionary<int, List<int>>();
  18. // 找出所有顶级节点(没有父节点的节点)
  19. var topDepartments = trees.Where(t => t.Type == "校区" || t.Type == "一级部门").ToList();
  20. foreach (var topDepartment in topDepartments)
  21. {
  22. List<int> subIds = new List<int>();
  23. // 递归收集当前顶级节点下的所有子节点ID
  24. CollectSubDepartmentIds(topDepartment, subIds);
  25. // 将结果添加到字典中
  26. subDepartmentIdsByTopDepartment[topDepartment.Id] = subIds;
  27. }
  28. return subDepartmentIdsByTopDepartment;
  29. }
  30. private void CollectSubDepartmentIds(Tree node, List<int> subDepartmentIds)
  31. {
  32. // 添加当前节点的ID(通常顶级节点不应该在这里添加,但在递归中保持一致性)
  33. // 注意:如果顶级节点的ID不应该出现在子节点列表中,则应该在此处进行条件判断
  34. // 例如:if (node.ParentId != null) subDepartmentIds.Add(node.Id);
  35. // 但由于我们是从顶级节点开始的,所以这里直接添加是安全的(对于子节点递归调用)
  36. subDepartmentIds.Add(node.Id);
  37. // 递归处理子节点
  38. foreach (var child in node.Child)
  39. {
  40. CollectSubDepartmentIds(child, subDepartmentIds);
  41. }
  42. }
  43. }
  44. // 示例用法
  45. public class Program
  46. {
  47. public static void Main()
  48. {
  49. // 假设这是从数据库中获取的所有Tree对象
  50. List<Tree> trees = new List<Tree>
  51. {
  52. // ...(填充示例数据)
  53. // 例如:
  54. // new Tree { Id = 1, Name = "顶级部门1", ParentId = null, Type = "一级部门", Child = new List<Tree> { ... } },
  55. // new Tree { Id = 2, Name = "顶级部门2", ParentId = null, Type = "一级部门", Child = new List<Tree> { ... } },
  56. // ...
  57. };
  58. TreeHelper helper = new TreeHelper();
  59. Dictionary<int, List<int>> allSubDepartmentIds = helper.GetAllSubDepartmentIds(trees);
  60. // 输出每个顶级部门及其所有子部门的ID
  61. foreach (var kvp in allSubDepartmentIds)
  62. {
  63. Console.WriteLine($"顶级部门ID: {kvp.Key}, 子部门ID: {string.Join(", ", kvp.Value)}");
  64. }
  65. }
  66. }

和树形结构表,关联的用户表,两个表一起解析出来数据

现在还有一个表,表结构如下:

  1. public class VAccountDepartment
  2. {
  3. public string AccountID { get; set; }
  4. public string Name { get; set; }
  5. public int? DepartID { get; set; }
  6. }

这里边的DepartID就是Tree里边的Id,每个tree里边的id都可能有这个数据,选中想把tree的子级也包含进行这块用户的数据。

为了将 VAccountDepartment 表与 Tree 表关联起来,并构建一个包含这些关联信息的树形结构,你需要对之前的逻辑进行一些调整。这里的关键是,你需要根据 VAccountDepartment 表中的 DepartID 来找到对应的 Tree 节点,并将 VAccountDepartment 实例附加到这些节点上。

以下是一个可能的实现方式:

  1. 首先,从数据库中获取 TreeVAccountDepartment 的所有数据。
  2. 构建 Tree 的树形结构,如之前所示。
  3. 遍历 VAccountDepartment 列表,将每个实例附加到对应的 Tree 节点上。

这里是一个修改后的代码示例:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. public class Tree
  5. {
  6. public int Id { get; set; }
  7. public string Name { get; set; }
  8. public int? ParentId { get; set; }
  9. public string Type { get; set; }
  10. public List<Tree> Child { get; set; } = new List<Tree>();
  11. public List<VAccountDepartment> Departments { get; set; } = new List<VAccountDepartment>();
  12. }
  13. public class VAccountDepartment
  14. {
  15. public string AccountID { get; set; }
  16. public string Name { get; set; }
  17. public int? DepartID { get; set; }
  18. }
  19. public class TreeBuilder
  20. {
  21. public List<Tree> BuildTreeWithDepartments(List<Tree> allTrees, List<VAccountDepartment> allDepartments)
  22. {
  23. // 构建树形结构
  24. var roots = BuildTree(allTrees);
  25. // 创建一个字典,方便根据 Id 快速查找树节点
  26. var treeLookup = roots.SelectMany(r => GetAllDescendants(r)).ToDictionary(t => t.Id);
  27. // 将 VAccountDepartment 实例附加到对应的 Tree 节点上
  28. foreach (var dept in allDepartments)
  29. {
  30. if (dept.DepartID.HasValue && treeLookup.TryGetValue(dept.DepartID.Value, out var treeNode))
  31. {
  32. treeNode.Departments.Add(dept);
  33. }
  34. // 如果需要处理 DepartID 为 null 的情况,可以在这里添加逻辑
  35. }
  36. return roots;
  37. }
  38. private List<Tree> BuildTree(List<Tree> allTrees)
  39. {
  40. // 查找根节点
  41. var roots = allTrees.Where(t => t.Type == "校区" || t.Type == "一级部门").ToList();
  42. // 递归函数,构建树形结构
  43. void BuildTreeRecursive(Tree parent)
  44. {
  45. foreach (var child in allTrees.Where(t => t.ParentId == parent.Id))
  46. {
  47. parent.Child.Add(child);
  48. BuildTreeRecursive(child);
  49. }
  50. }
  51. // 对每个根节点调用递归函数
  52. foreach (var root in roots)
  53. {
  54. BuildTreeRecursive(root);
  55. }
  56. return roots;
  57. }
  58. private IEnumerable<Tree> GetAllDescendants(Tree node)
  59. {
  60. return new[] { node }.Concat(node.Child.SelectMany(GetAllDescendants));
  61. }
  62. }
  63. // 示例用法
  64. public class Program
  65. {
  66. public static void Main()
  67. {
  68. // 假设这是从数据库中获取的所有 Tree 对象
  69. List<Tree> allTrees = new List<Tree>
  70. {
  71. // ...(示例数据)
  72. };
  73. // 假设这是从数据库中获取的所有 VAccountDepartment 对象
  74. List<VAccountDepartment> allDepartments = new List<VAccountDepartment>
  75. {
  76. // ...(示例数据)
  77. };
  78. TreeBuilder builder = new TreeBuilder();
  79. List<Tree> treeStructureWithDepartments = builder.BuildTreeWithDepartments(allTrees, allDepartments);
  80. // 输出或处理 treeStructureWithDepartments
  81. // ...
  82. }
  83. }

在这个示例中,BuildTreeWithDepartments 方法首先调用 BuildTree 来构建树形结构,然后创建一个字典 treeLookup 来存储所有树节点,以便快速查找。接下来,它遍历 allDepartments 列表,并将每个 VAccountDepartment 实例附加到对应的 Tree 节点上。GetAllDescendants 方法是一个辅助方法,用于递归地获取树的所有后代节点。

请注意,这个实现假设 DepartIDVAccountDepartment 表中是唯一的,并且每个 DepartID 都对应一个 Tree 节点。如果这不是情况,你可能需要添加一些额外的逻辑来处理重复或缺失的 DepartID 值。


欢迎加群讨论技术,1群:677373950(满了,可以加,但通过不了),2群:656732739。有需要软件开发,或者学习软件技术的朋友可以和我联系~(Q:815170684)

评价

git管理工具SourcetreeSetup介绍

SourceTree 是 Windows 和Mac OS X 下免费的 Git 和 Hg 客户端管理工具,同时也是Mn版本控制系统工具。支持创建、克隆、提...

layui简单树形组件layui tree

html:&lt;divid=&quot;test&quot;class=&quot;demo-tree-more&quot;&gt;&lt;/div&gt;js:layui.use([&#39;tree&#39;,&#39;ut...

layui树形组件动态选择layui tree

可以根据id来选中tree.setChecked(&#39;demoId1&#39;,[12,16]);//勾选指定节点获取树形id的用后台来就可以实现动态选中了//...

jstree添加点击事件

code show:$(&#39;#树形id&#39;).bind(&quot;activate_node.jstree&quot;,function(obj,e){ //获取当前节点 varcurrentNo...

jstree根据 id 获取节点方法:

jstree根据 ID 获取节点方法: var node = $(&#39;#树形id&#39;).jstree(&quot;get_node&quot;, id);

jstree自定义右键菜单

自定义右键菜单:重写contextmenu即可,把他放到contextmenu中$(&quot;#你的树形id&quot;).jstree({ contextmenu:{ }});代...

jstree默认展开、收起

默认展开 // 所有节点加载完成后触发 $(&#39;#jstree1&#39;).on(&quot;ready.jstree&quot;, function(e, data) { // ...

jstree自定义二级右键菜单

代码如下:语法其实就是submenu addfile: { &quot;label&quot;: &quot;新建&quot;, submenu: { addHtm...

jstree事件中拿来绑定的原始数据

比如要拿到绑定的id其实里边有个original属性就是绑定上来的原始对象,这样就可以随便的拿到了,这个树形组件封装得还是很...

js tree刷新数据

代码如下: var refreshTree = function () { var tree = $(&quot;#树形id&quot;); $.get(&#39;后台接口&#39;, ...

jstree获取当前选中节点与选中指定节点

获取jstree当前选中节点function getSelectNodeId() { var treeNode = $(&#39;#树形id&#39;).jstree(true).get_selected(t...

jstree的点击事件改变事件等

直接贴代码: //加载完成后触发的事件 $(&#39;#tree_3&#39;).on(&quot;ready.jstree&quot;, function (e, data) ...

c winform treeview最最基础的用法

最基本的添加与添加子节点publicpartialclassForm2:Form { publicForm2() { InitializeComponent(); //最基本的添加...

c treeview 获取点击的节点

方法一:点击事件+鼠标按下事件如果直接用点击事件获取到的是上一次的节点,有问题所以拿一个更早的鼠标按下事件来设置一下...

c treeview点击事件获取的是上一次的

可以使用鼠标按下事件解决,如果直接用点击事件获取到的是上一次的节点,有问题所以拿一个更早的鼠标按下事件来设置一下选...

treeview添加右键事件二级右键菜单

代码如下:publicpartialclassForm1:Form { publicForm1() { InitializeComponent(); treeView1.Nodes.Add(&quot;aa...
这一生多幸运赶上过你.
排名
8
文章
243
粉丝
7
评论
7
ICP备案 :渝ICP备18016597号-1
网站信息:2018-2025TNBLOG.NET
技术交流:群号656732739
联系我们:contact@tnblog.net
公网安备:50010702506256
欢迎加群交流技术