树结构工具-TreeUtil
# 简介
考虑到菜单等需求的普遍性,有用户提交了一个扩展性极好的树状结构实现。这种树状结构可以根据配置文件灵活的定义节点之间的关系,也能很好的兼容关系数据库中数据。实现
关系型数据库数据 <-> Tree <-> JSON
我们假设要构建一个菜单,可以实现系统管理和店铺管理,菜单的样子如下:
系统管理
|- 用户管理
|- 添加用户
店铺管理
|- 商品管理
|- 添加商品
那这种结构如何保存在数据库中呢?一般是这样的:
id | parentId | name | weight |
---|---|---|---|
1 | 0 | 系统管理 | 5 |
11 | 1 | 用户管理 | 10 |
111 | 1 | 用户添加 | 11 |
2 | 0 | 店铺管理 | 5 |
21 | 2 | 商品管理 | 10 |
221 | 2 | 添加添加 | 11 |
我们看到,每条数据根据parentId相互关联并表示层级关系,parentId
在这里也叫外键。
静态工具类 TreeUtil, 是一个树工具类,它提供了以下功能:构建树、获取根节点、获取父节点、获取子节点、获取深度、获取祖先、获取后代、获取兄弟节点、判断是否是叶子节点、获取最大深度、获取最小深度、获取下一个兄弟节点、获取上一个兄弟节点、获取首个子节点、获取最后一个子节点、获取节点数量、获取叶子节点数量、获取权重和、获取叶子节点权重和、获取平均深度、获取平均权重、获取最大权重、获取最小权重。
# EasyTool.TreeUtil 类
方法说明:
BuildTree
: 构建树GetRoot
: 获取根节点GetParent
: 获取父节点GetChildren
: 获取子节点GetDepth
: 获取深度GetAncestors
: 获取祖先GetDescendants
: 获取后代GetSiblings
: 获取兄弟节点IsLeaf
: 判断是否是叶子节点GetMaxDepth
: 获取最大深度GetMinDepth
: 获取最小深度GetNextSibling
: 获取下一个兄弟节点GetPreviousSibling
: 获取上一个兄弟节点GetFirstChild
: 获取首个子节点GetLastChild
: 获取最后一个子节点GetNodeCount
: 获取节点数量GetLeafCount
: 获取叶子节点数量GetTotalWeight
: 获取权重和GetLeafWeightTotal
: 获取叶子节点权重和GetAverageDepth
: 获取平均深度GetAverageWeight
: 获取平均权重GetMaxWeight
: 获取最大权重GetMinWeight
: 获取最小权重
# 构造函数
/// <summary>
/// 构造函数
/// </summary>
/// <param name="nodes">树节点列表</param>
public TreeUtil(List<TreeNode<T, D>> nodes)
# BuildTree-构建树结构
/// <summary>
/// 构建树结构
/// </summary>
/// <returns>根节点</returns>
public TreeNode<T, D> BuildTree()
# GetParents-获取某个节点的所有父节点
/// <summary>
/// 获取某个节点的所有父节点
/// </summary>
/// <param name="node">节点</param>
/// <returns>父节点列表,从根节点到该节点的顺序</returns>
public List<TreeNode<T, D>> GetParents(TreeNode<T, D> node)
# GetDepth-获取某个节点的深度
/// <summary>
/// 获取某个节点的深度
/// </summary>
/// <param name="node">节点</param>
/// <returns>节点深度,根节点的深度为0</returns>
public int GetDepth(TreeNode<T, D> node)
# GetDescendants-获取某个节点的所有子孙节点
/// <summary>
/// 获取某个节点的所有子孙节点
/// </summary>
/// <param name="node">节点</param>
/// <returns>子孙节点列表</returns>
public List<TreeNode<T, D>> GetDescendants(TreeNode<T, D> node)
# GetSiblings-获取某个节点的所有兄弟节点
/// <summary>
/// 获取某个节点的所有兄弟节点
/// </summary>
/// <param name="node">节点</param>
/// <returns>兄弟节点列表</returns>
public List<TreeNode<T, D>> GetSiblings(TreeNode<T, D> node)
# GetSiblingCount-获取某个节点的所有兄弟节点数量
/// <summary>
/// 获取某个节点的所有兄弟节点数量
/// </summary>
/// <param name="node">节点</param>
/// <returns>兄弟节点数量</returns>
public int GetSiblingCount(TreeNode<T, D> node)
# IsLeaf-判断某个节点是否是叶子节点
/// <summary>
/// 判断某个节点是否是叶子节点
/// </summary>
/// <param name="node">节点</param>
/// <returns>是否是叶子节点</returns>
public bool IsLeaf(TreeNode<T, D> node)
# GetMaxDepth-获取树的最大深度
/// <summary>
/// 获取树的最大深度
/// </summary>
/// <returns>树的最大深度</returns>
public int GetMaxDepth()
# GetMinDepth-获取树的最小深度
/// <summary>
/// 获取树的最小深度
/// </summary>
/// <returns>树的最小深度</returns>
public int GetMinDepth()
# GetNextSibling-获取某个节点的下一个兄弟节点
/// <summary>
/// 获取某个节点的下一个兄弟节点
/// </summary>
/// <param name="node">节点</param>
/// <returns>下一个兄弟节点</returns>
public TreeNode<T, D> GetNextSibling(TreeNode<T, D> node)
# GetPreviousSibling-获取某个节点的上一个兄弟节点
/// <summary>
/// 获取某个节点的上一个兄弟节点
/// </summary>
/// <param name="node">节点</param>
/// <returns>上一个兄弟节点</returns>
public TreeNode<T, D> GetPreviousSibling(TreeNode<T, D> node)
# GetFirstChild-获取某个节点的首个子节点
/// <summary>
/// 获取某个节点的首个子节点
/// </summary>
/// <param name="node">节点</param>
/// <returns>首个子节点</returns>
public TreeNode<T, D> GetFirstChild(TreeNode<T, D> node)
# GetLastChild-获取某个节点的最后一个子节点
/// <summary>
/// 获取某个节点的最后一个子节点
/// </summary>
/// <param name="node">节点</param>
/// <returns>最后一个子节点</returns>
public TreeNode<T, D> GetLastChild(TreeNode<T, D> node)
# GetNodeCount-获取树的所有节点数量
/// <summary>
/// 获取树的所有节点数量
/// </summary>
/// <returns>树的所有节点数量</returns>
public int GetNodeCount()
# GetLeafCount-获取树的所有叶子节点数量
/// <summary>
/// 获取树的所有叶子节点数量
/// </summary>
/// <returns>树的所有叶子节点数量</returns>
public int GetLeafCount()
# GetTotalWeight-获取树的所有节点的权重和
/// <summary>
/// 获取树的所有节点的权重和
/// </summary>
/// <returns>树的所有节点的权重和</returns>
public int GetTotalWeight()
# GetLeafWeightTotal-获取树的所有叶子节点的权重和
/// <summary>
/// 获取树的所有叶子节点的权重和
/// </summary>
/// <returns>树的所有叶子节点的权重和</returns>
public int GetLeafWeightTotal()
# GetAverageDepth-获取树的平均深度
/// <summary>
/// 获取树的平均深度
/// </summary>
/// <returns>树的平均深度</returns>
public int GetAverageDepth()
# GetAverageWeight-获取树的平均节点权重
/// <summary>
/// 获取树的平均节点权重
/// </summary>
/// <returns>树的平均节点权重</returns>
public int GetAverageWeight()
# GetMaxWeight-获取树的最大节点权重
/// <summary>
/// 获取树的最大节点权重
/// </summary>
/// <returns>树的最大节点权重</returns>
public int GetMaxWeight()
# GetMinWeight-获取树的最小节点权重
/// <summary>
/// 获取树的最小节点权重
/// </summary>
/// <returns>树的最小节点权重</returns>
public int GetMinWeight()
# 代码示例
using System;
using System.Linq;
namespace TreeUtilExample
{
class Program
{
static void Main(string[] args)
{
// 创建树节点数据
var nodes = new TreeNode<int, string>[]
{
new TreeNode<int, string>(1, 0, "A", 10, "Node A"),
new TreeNode<int, string>(2, 1, "B", 20, "Node B"),
new TreeNode<int, string>(3, 1, "C", 30, "Node C"),
new TreeNode<int, string>(4, 2, "D", 40, "Node D"),
new TreeNode<int, string>(5, 2, "E", 50, "Node E"),
new TreeNode<int, string>(6, 3, "F", 60, "Node F"),
new TreeNode<int, string>(7, 3, "G", 70, "Node G"),
new TreeNode<int, string>(8, 4, "H", 80, "Node H"),
new TreeNode<int, string>(9, 5, "I", 90, "Node I"),
new TreeNode<int, string>(10, 6, "J", 100, "Node J"),
new TreeNode<int, string>(11, 7, "K", 110, "Node K"),
};
// 构建树
var tree = new TreeUtil<int, string>(nodes);
// 获取根节点
var root = tree.GetRoot();
Console.WriteLine("Root: " + root.Name);
// 获取父节点
var parent = tree.GetParent(5);
Console.WriteLine("Parent of Node E: " + parent.Name);
// 获取子节点
var children = tree.GetChildren(1);
Console.WriteLine("Children of Node A: " + string.Join(", ", children.Select(c => c.Name)));
// 获取深度
var depth = tree.GetDepth(11);
Console.WriteLine("Depth of Node K: " + depth);
// 获取祖先
var ancestors = tree.GetAncestors(11);
Console.WriteLine("Ancestors of Node K: " + string.Join(", ", ancestors.Select(a => a.Name)));
// 获取后代
var descendants = tree.GetDescendants(1);
Console.WriteLine("Descendants of Node A: " + string.Join(", ", descendants.Select(d => d.Name)));
// 获取兄弟节点
var siblings = tree.GetSiblings(5);
Console.WriteLine("Siblings of Node E: " + string.Join(", ", siblings.Select(s => s.Name)));
}
}
}
# 输出结果
Root: A
Parent of Node E: B
Children of Node A: B, C
Depth of Node K: 4
Ancestors of Node K: G, C, A
Descendants of Node A: B, C, D, E, H, I, F, J, K
Siblings of Node E: D
上次更新: 2023/04/26, 22:10:06