ForestMap
# 功能介绍
ForestMap是Hutool中提供的支持树形结构的Map实现,它允许将Map组织成树形结构,支持父子节点关系的管理。通过ForestMap,可以方便地创建、遍历和操作树形数据结构,适用于各种需要层级关系的数据场景。
# 主要特性
- 支持树形结构,允许父子节点关系
- 支持添加、删除、修改节点
- 支持遍历树形结构(深度优先、广度优先)
- 支持获取节点的父节点、子节点、祖先节点和后代节点
- 支持判断节点关系(是否为父节点、子节点、祖先节点、后代节点)
- 支持将树形结构转换为列表或其他数据结构
- 线程不安全,建议在单线程环境下使用
# 适用场景
- 组织架构数据管理
- 分类目录管理
- 菜单权限管理
- 树形配置数据管理
- 任何需要层级关系的数据场景
- 家谱树、思维导图等树形结构
# 使用示例
# 示例1:基本用法
// 创建ForestMap
ForestMap<String, String> forestMap = new ForestMap<>();
// 添加根节点
forestMap.addRoot("root", "根节点");
// 添加子节点
forestMap.addChild("root", "child1", "子节点1");
forestMap.addChild("root", "child2", "子节点2");
forestMap.addChild("child1", "grandchild1", "孙子节点1");
forestMap.addChild("child1", "grandchild2", "孙子节点2");
forestMap.addChild("child2", "grandchild3", "孙子节点3");
// 获取节点
String rootValue = forestMap.get("root");
// 输出: 根节点
// 获取子节点列表
List<String> children = forestMap.getChildrenKeys("root");
// 输出: [child1, child2]
// 获取所有后代节点
List<String> descendants = forestMap.getDescendantKeys("child1");
// 输出: [grandchild1, grandchild2]
# 示例2:遍历树形结构
ForestMap<String, String> forestMap = new ForestMap<>();
forestMap.addRoot("root", "根节点");
forestMap.addChild("root", "child1", "子节点1");
forestMap.addChild("root", "child2", "子节点2");
forestMap.addChild("child1", "grandchild1", "孙子节点1");
// 深度优先遍历
Console.log("深度优先遍历:");
forestMap.traverseDepthFirst("root", (node) -> {
Console.log("- ".repeat(node.getLevel()) + node.getKey() + "=" + node.getValue());
});
// 输出:
// 深度优先遍历:
// root=根节点
// - child1=子节点1
// -- grandchild1=孙子节点1
// - child2=子节点2
// 广度优先遍历
Console.log("\n广度优先遍历:");
forestMap.traverseBreadthFirst("root", (node) -> {
Console.log("- ".repeat(node.getLevel()) + node.getKey() + "=" + node.getValue());
});
// 输出:
// 广度优先遍历:
// root=根节点
// - child1=子节点1
// - child2=子节点2
// -- grandchild1=孙子节点1
# 示例3:节点关系判断
ForestMap<String, String> forestMap = new ForestMap<>();
forestMap.addRoot("root", "根节点");
forestMap.addChild("root", "child1", "子节点1");
forestMap.addChild("child1", "grandchild1", "孙子节点1");
// 判断父子关系
boolean isParent = forestMap.isParent("root", "child1");
// 输出: true
boolean isChild = forestMap.isChild("child1", "root");
// 输出: true
// 判断祖先后代关系
boolean isAncestor = forestMap.isAncestor("root", "grandchild1");
// 输出: true
boolean isDescendant = forestMap.isDescendant("grandchild1", "root");
// 输出: true
# 示例4:删除节点
ForestMap<String, String> forestMap = new ForestMap<>();
forestMap.addRoot("root", "根节点");
forestMap.addChild("root", "child1", "子节点1");
forestMap.addChild("child1", "grandchild1", "孙子节点1");
// 删除子节点及其所有后代
forestMap.remove("child1");
// 检查子节点是否存在
boolean existsChild1 = forestMap.containsKey("child1");
// 输出: false
boolean existsGrandchild1 = forestMap.containsKey("grandchild1");
// 输出: false
# 注意事项
- ForestMap是线程不安全的,在多线程环境下使用需要额外同步
- 支持多个根节点,可以通过addRoot()方法添加多个根节点
- 删除节点时,会同时删除该节点的所有后代节点
- 节点的key必须唯一,添加重复key会覆盖原有节点
- 支持null值,但不支持null key
- 遍历方法提供了深度优先和广度优先两种方式
- 可以通过getNode()方法获取完整的节点对象,包含层级、父节点等信息
# 方法列表
| 方法名 | 描述 | 参数 | 返回值 |
|---|---|---|---|
| addRoot(K key, V value) | 添加根节点 | key: 节点键, value: 节点值 | ForestMap<K, V> |
| addChild(K parentKey, K childKey, V value) | 添加子节点 | parentKey: 父节点键, childKey: 子节点键, value: 子节点值 | ForestMap<K, V> |
| get(K key) | 获取节点值 | key: 节点键 | V |
| getNode(K key) | 获取节点对象 | key: 节点键 | ForestMap.Node<K, V> |
| getChildrenKeys(K key) | 获取子节点键列表 | key: 节点键 | List |
| getChildren(K key) | 获取子节点映射 | key: 节点键 | Map<K, V> |
| getParentKey(K key) | 获取父节点键 | key: 节点键 | K |
| getParent(K key) | 获取父节点值 | key: 节点键 | V |
| getAncestorKeys(K key) | 获取祖先节点键列表 | key: 节点键 | List |
| getDescendantKeys(K key) | 获取后代节点键列表 | key: 节点键 | List |
| isRoot(K key) | 判断是否为根节点 | key: 节点键 | boolean |
| isLeaf(K key) | 判断是否为叶子节点 | key: 节点键 | boolean |
| isParent(K parentKey, K childKey) | 判断是否为父节点 | parentKey: 父节点键, childKey: 子节点键 | boolean |
| isChild(K childKey, K parentKey) | 判断是否为子节点 | childKey: 子节点键, parentKey: 父节点键 | boolean |
| isAncestor(K ancestorKey, K descendantKey) | 判断是否为祖先节点 | ancestorKey: 祖先节点键, descendantKey: 后代节点键 | boolean |
| isDescendant(K descendantKey, K ancestorKey) | 判断是否为后代节点 | descendantKey: 后代节点键, ancestorKey: 祖先节点键 | boolean |
| traverseDepthFirst(K startKey, Consumer<ForestMap.Node<K, V>> consumer) | 深度优先遍历 | startKey: 起始节点键, consumer: 节点处理器 | void |
| traverseBreadthFirst(K startKey, Consumer<ForestMap.Node<K, V>> consumer) | 广度优先遍历 | startKey: 起始节点键, consumer: 节点处理器 | void |
| remove(K key) | 删除节点及其所有后代 | key: 节点键 | V |
| clear() | 清空ForestMap | 无 | void |
| size() | 获取节点总数 | 无 | int |