This commit is contained in:
Looly 2022-08-11 21:06:32 +08:00
parent 460d010cc0
commit 629507cbaf
3 changed files with 57 additions and 81 deletions

View File

@ -11,7 +11,10 @@ import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Stack;
import java.util.function.Consumer;
import java.util.function.Predicate;
@ -187,16 +190,47 @@ public class Tree<T> extends LinkedHashMap<String, Object> implements Node<T> {
}
/**
* 递归树并处理子树下的节点
* 递归树并处理子树下的节点采用深度优先遍历方式
*
* @param consumer 节点处理器
* @since 5.7.16
*/
public void walk(final Consumer<Tree<T>> consumer) {
consumer.accept(this);
final List<Tree<T>> children = getChildren();
if (CollUtil.isNotEmpty(children)) {
children.forEach((tree) -> tree.walk(consumer));
walk(consumer, false);
}
/**
* 递归树并处理子树下的节点
*
* @param consumer 节点处理器
* @param broadFirst 是否广度优先遍历
* @since 6.0.0
*/
public void walk(final Consumer<Tree<T>> consumer, final boolean broadFirst) {
if (broadFirst) { // 广度优先遍历
// 加入FIFO队列
final Queue<Tree<T>> queue = new LinkedList<>();
queue.offer(this);
while (false == queue.isEmpty()) {
final Tree<T> node = queue.poll();
consumer.accept(node);
final List<Tree<T>> children = node.getChildren();
if (CollUtil.isNotEmpty(children)) {
children.forEach(queue::offer);
}
}
} else { // 深度优先遍历
// 入栈,FILO
final Stack<Tree<T>> stack = new Stack<>();
stack.add(this);
while (false == stack.isEmpty()) {
final Tree<T> node = stack.pop();
consumer.accept(node);
final List<Tree<T>> children = node.getChildren();
if (CollUtil.isNotEmpty(children)) {
children.forEach(stack::push);
}
}
}
}

View File

@ -6,12 +6,9 @@ import cn.hutool.core.tree.parser.NodeParser;
import cn.hutool.core.util.ObjUtil;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Queue;
import java.util.Stack;
/**
* 树工具类
@ -241,88 +238,21 @@ public class TreeUtil {
return new Tree<E>().setId(id);
}
/**
* 深度优先,遍历森林,将森林转换为数组
*
* @param forest 森林
* @param <E> 节点ID类型
* @return 森林所有节点列表
*/
public static <E> List<Tree<E>> deepFirstForestConvertToList(List<Tree<E>> forest) {
if (CollUtil.isEmpty(forest)) {
return null;
}
List<Tree<E>> list = new ArrayList<>();
forest.forEach(root -> list.addAll(Objects.requireNonNull(deepFirstTreeConvertToList(root))));
return list;
}
/**
* 广度优先,遍历森林,将森林转换为数组
*
* @param forest 森林
* @param <E> 节点ID类型
* @return 森林所有节点列表
*/
public static <E> List<Tree<E>> broadFirstForestConvertToList(List<Tree<E>> forest) {
if (CollUtil.isEmpty(forest)) {
return null;
}
List<Tree<E>> list = new ArrayList<>();
forest.forEach(root -> list.addAll(Objects.requireNonNull(broadFirstTreeConvertToList(root))));
return list;
}
/**
* 深度优先,遍历树,将树换为数组
*
* @param root 树的根节点
* @param <E> 节点ID类型
* @param root 树的根节点
* @param broadFirst 是否广度优先遍历
* @param <E> 节点ID类型
* @return 树所有节点列表
*/
public static <E> List<Tree<E>> deepFirstTreeConvertToList(Tree<E> root) {
public static <E> List<Tree<E>> toList(final Tree<E> root, final boolean broadFirst) {
if (Objects.isNull(root)) {
return null;
}
final List<Tree<E>> list = new ArrayList<>();
root.walk(list::add, broadFirst);
// 入栈,FILO
List<Tree<E>> list = new ArrayList<>();
Stack<Tree<E>> stack = new Stack<>();
stack.add(root);
while (!stack.isEmpty()) {
Tree<E> node = stack.pop();
list.add(node);
if (node.hasChild()) {
node.getChildren().forEach(stack::push);
}
}
return list;
}
/**
* 广度优先,遍历树,将树转换为数组
*
* @param root 树的根节点
* @param <E> 节点ID类型
* @return 树所有节点列表
*/
public static <E> List<Tree<E>> broadFirstTreeConvertToList(Tree<E> root) {
if (Objects.isNull(root)) {
return null;
}
// 加入FIFO队列
List<Tree<E>> list = new ArrayList<>();
Queue<Tree<E>> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
Tree<E> node = queue.poll();
list.add(node);
if (node.hasChild()) {
node.getChildren().forEach(queue::offer);
}
}
return list;
}
}

View File

@ -1,6 +1,7 @@
package cn.hutool.core.tree;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.lang.Console;
import org.junit.Assert;
import org.junit.Test;
@ -77,6 +78,17 @@ public class TreeTest {
Assert .assertEquals(7, ids.size());
}
@Test
public void walkBroadFirstTest(){
final List<String> ids = new ArrayList<>();
final Tree<String> tree = TreeUtil.buildSingle(nodeList, "0");
Console.log(tree);
tree.walk((tr)-> ids.add(tr.getId()), true);
Console.log(ids);
Assert .assertEquals(7, ids.size());
}
@Test
public void cloneTreeTest(){
final Tree<String> tree = TreeUtil.buildSingle(nodeList, "0");