cn.kdyzm.util.tree.TreeUtils Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of kdyzm-util Show documentation
Show all versions of kdyzm-util Show documentation
常用工具类整理,包含jackson、http请求、树构建工具、web工具类等
The newest version!
package cn.kdyzm.util.tree;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
/**
*
* 树构建工具类
*
*
* @author kdyzm
* @since 2021-05-18 16:21:19
*/
public final class TreeUtils {
private static class Pair {
final T element;
boolean mark;
int deep;
private Pair(T element, boolean mark, int deep) {
this.element = element;
this.mark = mark;
this.deep = deep;
}
static Pair of(T element, boolean mark) {
return new Pair<>(element, mark, 0);
}
static Pair of(T element, boolean mark, int deep) {
return new Pair<>(element, mark, deep);
}
}
/**
* 生成常规的树同层比较器
*
* @param
* @param comparator 比较器
* @param childFunction 获取孩子链表
* @return
*/
public static Consumer> generateSortConsumer(Comparator comparator,
Function> childFunction) {
return new Consumer>() {
@Override
public void accept(List list) {
Collections.sort(list, comparator);
for (T model : list) {
List childList = childFunction.apply(model);
if (Objects.nonNull(childList) && !childList.isEmpty()) {
this.accept(childFunction.apply(model));
}
}
}
};
}
/**
* 生成常规的树同层比较器
*
* @param extends Comparable super T>
* @param childFunction 获取孩子链表
* @return
*/
public static > Consumer> generateSortConsumer(
Function> childFunction) {
return new Consumer>() {
@Override
public void accept(List list) {
Collections.sort(list);
for (T model : list) {
List childList = childFunction.apply(model);
if (Objects.nonNull(childList) && !childList.isEmpty()) {
this.accept(childFunction.apply(model));
}
}
}
};
}
/**
* 将集合内数据组装成树形结构
* 注意不得有重复数据,若有则存在丢失的可能
*
* @param 模型
* @param key类型
* @param elements 数据
* @param keyFunction 获取key的方法
* @param parentKeyFunction 获取父key的方法
* @param addChildConsumer 向模型添加孩子的方法
* @return {@link ArrayList}
*/
public static List formatToTree(Collection elements, Function keyFunction,
Function parentKeyFunction, BiConsumer addChildConsumer) {
return formatToTree(elements, keyFunction, parentKeyFunction, addChildConsumer, null);
}
/**
* 将集合内数据组装成树形结构
* 注意不得有重复数据,若有则存在丢失的可能
*
* @param 模型
* @param key类型
* @param elements 数据
* @param keyFunction 获取key的方法
* @param parentKeyFunction 获取父key的方法
* @param addChildConsumer 向模型添加孩子的方法
* @param sortConsumer 排序方法,可通过 {@link #generateSortConsumer(Function)} 或
* {@link #generateSortConsumer(Comparator, Function)}
* 方式快速成功,但是孩子节点必须要用list保存
* @return {@link ArrayList}
*/
public static List formatToTree(Collection elements, Function keyFunction, Function parentKeyFunction, BiConsumer addChildConsumer, Consumer> sortConsumer) {
return formatToTree(elements, keyFunction, parentKeyFunction, addChildConsumer, sortConsumer, null);
}
/**
* 将集合内数据组装成树形结构
* 注意不得有重复数据,若有则存在丢失的可能
*
* @param 模型
* @param key类型
* @param elements 数据
* @param keyFunction 获取key的方法
* @param parentKeyFunction 获取父key的方法
* @param addChildConsumer 向模型添加孩子的方法
* @param sortConsumer 排序方法,可通过 {@link #generateSortConsumer(Function)} 或
* {@link #generateSortConsumer(Comparator, Function)}
* 方式快速成功,但是孩子节点必须要用list保存
* @param isRootFunction 判断是否是根节点方法,若为null,则表示直到找不到上层便为根节点
* @return {@link ArrayList}
*/
public static List formatToTree(Collection elements, Function keyFunction, Function parentKeyFunction, BiConsumer addChildConsumer, Consumer> sortConsumer, Function isRootFunction) {
return formatToTree(elements, keyFunction, parentKeyFunction, addChildConsumer, sortConsumer, isRootFunction, 0);
}
/**
* 将集合内数据组装成树形结构
* 注意不得有重复数据,若有则存在丢失的可能
*
* @param 模型
* @param key类型
* @param elements 数据
* @param keyFunction 获取key的方法
* @param parentKeyFunction 获取父key的方法
* @param addChildConsumer 向模型添加孩子的方法
* @param sortConsumer 排序方法,可通过 {@link #generateSortConsumer(Function)} 或
* {@link #generateSortConsumer(Comparator, Function)}
* 方式快速成功,但是孩子节点必须要用list保存
* @param isRootFunction 判断是否是根节点方法,若为null,则表示直到找不到上层便为根节点
* @param deep 最大深度,若 <=0 则表示无限深(不进行截取)
* @return {@link ArrayList}
*/
public static List formatToTree(Collection elements, Function keyFunction, Function parentKeyFunction, BiConsumer addChildConsumer, Consumer> sortConsumer, Function isRootFunction, int deep) {
if (Objects.isNull(elements) || elements.isEmpty()) {
return Collections.emptyList();
}
// 元素map,将所有权限list转换为hashMap,这样可以将查找复杂度变为O(1)
final HashMap> elementMap = new HashMap<>(elements.size());
// 将list元素转换为map元素
for (T element : elements) {
K key = keyFunction.apply(element);
elementMap.put(key, Pair.of(element, false, 0));
}
// 根元素,在最终组装完结后,将最后的元素加入到子列表中
final List rootList = new ArrayList<>();
// 检查元素回环的方法,如果本次“倒桩”组成时,发现已经存在过则说明发生了回环
HashSet alreadySet = new HashSet<>();
for (Map.Entry> entry : elementMap.entrySet()) {
final K key = entry.getKey();
// 一定会存在的!!!
final Pair pair = entry.getValue();
// 如果用过了,就不在查找了
if (pair.mark) {
continue;
}
// 每次都要清空,因为每次“倒桩”组成树都是一次独立的枝条
alreadySet.clear();
alreadySet.add(key);
Deque> stack = new LinkedList<>();
stack.push(pair);
// 在寻找的路径中,某个元素被使用过,说明前面已经寻找过
for (Pair currentPair = pair; !currentPair.mark; ) {
currentPair.mark = true;
if (Objects.nonNull(isRootFunction) && isRootFunction.apply(currentPair.element)) {
rootList.add(currentPair.element);
break;
}
// 获取父节点
final K parentKey = parentKeyFunction.apply(currentPair.element);
Pair parentPair = elementMap.get(parentKey);
// 如果不存在父节点,则认为是根节点
if (Objects.isNull(parentPair)) {
// 如果有了根节点判断依据,则不加入根节点列表
if (Objects.isNull(isRootFunction)) {
rootList.add(currentPair.element);
}
break;
}
// 如果已经被加入过,则说明存在回环,存在 1->2->1 的问题,因为parent可能被使用过
if (alreadySet.contains(parentKey)) {
throw new IllegalStateException("has loopback!loopback key is [" + parentKey + "]");
}
alreadySet.add(parentKey);
stack.push(parentPair);
// 继续寻找上层元素
currentPair = parentPair;
}
// 从上而下加入子节点
{
Pair parentPair = stack.pop();
while (!stack.isEmpty()) {
Pair currentPair = stack.pop();
currentPair.deep = parentPair.deep + 1;
if (deep > 0 && currentPair.deep >= deep) {
// 后面的不管怎么加,也已经从当前截断了,从而可以做剪枝
break;
}
addChildConsumer.accept(parentPair.element, currentPair.element);
parentPair = currentPair;
}
}
}
if (Objects.nonNull(sortConsumer)) {
sortConsumer.accept(rootList);
}
return rootList;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy