Java树结构通用工具类
Java树结构通用工具类
- Maven依赖
- TreeUtil
可进行树的生成,节点查找,根据规则剪枝操作。
Maven依赖
<dependencies>
<dependency>
<groupId>io.vavr</groupId>
<artifactId>vavr</artifactId>
<version>0.10.4</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.4</version>
</dependency>
</dependencies>
TreeUtil
import io.vavr.collection.Array;
import org.apache.commons.collections4.CollectionUtils;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Predicate;
public class TreeUtil {
public static abstract class TreeNode<T> {
private transient TreeNode<T> parent;
/**
* 树节点id
*/
public abstract T id();
/**
* 获取该节点的父节点id
*/
public abstract T parentId();
/**
* 是否是根节点
*/
public abstract boolean root();
/**
* 设置节点的子节点列表
*/
public abstract void putChildren(List<? extends TreeNode<T>> children);
public abstract List<? extends TreeNode<T>> takeChildren();
protected void putParent(TreeNode<T> parent) {
this.parent = parent;
}
protected TreeNode<T> takeParent() {
return this.parent;
}
}
/**
* 根据所有树节点列表,生成含有所有树形结构的列表
*/
public static <E extends TreeNode<T>, T> List<E> generateTrees(List<E> nodes) {
List<E> roots = new ArrayList<>();
for (Iterator<E> item = nodes.iterator(); item.hasNext(); ) {
E node = item.next();
//如果是根节点
if (node.root()) {
roots.add(node);
//从所有节点列表中删除该节点,以免后续重复遍历该节点
item.remove();
}
}
roots.forEach(e -> setChildren(e, nodes));
return roots;
}
/**
* 根据规则筛选树(减枝,并保留父节点)
*/
@SuppressWarnings("unchecked")
public static <E extends TreeNode<T>, T> List<E> selectByRule(List<E> nodes, Predicate<E> rule) {
if (CollectionUtils.isEmpty(nodes)) {
return Collections.emptyList();
}
LinkedList<E> linkedList = new LinkedList<>(nodes);
List<E> list = new ArrayList<>();
E e;
while ((e = linkedList.poll()) != null) {
List<? extends TreeNode<T>> children = e.takeChildren();
if (CollectionUtils.isNotEmpty(children)) {
for (TreeNode<T> child : children) {
child.putParent(e);
linkedList.offer((E) child);
}
}
if (rule.test(e)) {
list.addAll(findParents(e));
}
}
Array<E> array = Array.ofAll(list).distinctBy(TreeNode::id);
array.forEach(ele -> ele.putChildren(null));
return generateTrees(array.asJavaMutable());
}
/**
* 深度优先遍历树
*/
@SuppressWarnings("unchecked")
public static <E extends TreeNode<T>, T> void dfsTree(E e, Consumer<E> action) {
if (e != null) {
action.accept(e);
List<? extends TreeNode<T>> children = e.takeChildren();
if (CollectionUtils.isNotEmpty(children)) {
for (TreeNode<T> child : children) {
dfsTree((E) child, action);
}
}
}
}
/**
* 广度优先遍历树,action为(父节点,子节点)的操作,用于处理树节点之间的关系
*/
@SuppressWarnings("unchecked")
public static <E extends TreeNode<T>, T> void bfsTree(E e, BiConsumer<E, E> action) {
LinkedList<E> linkedList = new LinkedList<>();
linkedList.add(e);
E temp;
while ((temp = linkedList.poll()) != null) {
List<? extends TreeNode<T>> children = temp.takeChildren();
if (CollectionUtils.isNotEmpty(children)) {
for (TreeNode<T> child : children) {
action.accept(temp, (E) child);
linkedList.offer((E) child);
}
}
}
}
/**
* 根据id查找树节点
*/
@SuppressWarnings("unchecked")
public static <E extends TreeNode<T>, T> E findNodeById(E node, T id) {
if (node != null) {
T nodeId = node.id();
if (Objects.equals(nodeId, id)) {
return node;
}
List<? extends TreeNode<T>> children = node.takeChildren();
if (CollectionUtils.isNotEmpty(children)) {
for (TreeNode<T> child : children) {
E nd = (E) findNodeById(child, id);
if (nd != null) {
return nd;
}
}
}
}
return null;
}
/**
* 从所有节点列表中查找并设置parent的所有子节点
*
* @param parent 父节点
* @param nodes 所有树节点列表
*/
private static <E extends TreeNode<T>, T> void setChildren(E parent, List<E> nodes) {
List<E> children = new ArrayList<>();
Object parentId = parent.id();
for (Iterator<E> iterator = nodes.iterator(); iterator.hasNext(); ) {
E node = iterator.next();
if (Objects.equals(node.parentId(), parentId)) {
children.add(node);
//从所有节点列表中删除该节点,以免后续重复遍历该节点
iterator.remove();
}
}
//如果孩子为空,则直接返回,否则继续遍历递归设置孩子的孩子
if (children.isEmpty()) {
return;
}
parent.putChildren(children);
children.forEach(e -> setChildren(e, nodes));
}
@SuppressWarnings("unchecked")
private static <E extends TreeNode<T>, T> List<E> findParents(E e) {
List<E> list = new ArrayList<>();
list.add(e);
E temp = e;
while ((temp = (E) temp.takeParent()) != null) {
list.add(temp);
}
return list;
}
}