本文分两段.1普通树转二叉树代码(普通树为Hutool的jar的树).2基于以上做了个EasyExcel 动态表头工具类
一.普通树转二叉树
一般树的结构中有4个基础属性(id,name,parentId,children)
算了,文案懒得写了,直接上代码。
1.BTreeUtil(转换工具类)
import cn.hutool.core.lang.tree.Tree;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.collections4.CollectionUtils;
import java.util.ArrayList;
import java.util.List;
/**
* @Description TODO 普通树转二叉树
* @ClassName BTreeUtil.java
* @createTime 2022年05月24日 17:15:00
* @author YH
*/
public class BTreeUtil {
public static BinaryTreeNode convertTreeToBinaryTree(Tree root) {
if (root == null) {
return null;
}
BinaryTreeNode binaryRoot = convertNode(root);
//赋值
binaryRoot.setId(root.getId().toString());
binaryRoot.setParentId(root.getParentId().toString());
// 因为Hutool工具类把没有子集的children隐藏了,这里做下判断,不然会报空指针异常
Object o = JSON.toJSON(root);
JSONObject jsonObj = new JSONObject();
if (o instanceof JSONObject) {
jsonObj = (JSONObject) o;
}
if (jsonObj.containsKey("children")) {
BinaryTreeNode left = convertChildren(root.getChildren());
left.setParentId(binaryRoot.getId());
binaryRoot.setLeft(left);
// 根据业务需求,判断是否在 普通树 中还有子集
binaryRoot.setIsChildren(CollectionUtils.isEmpty(root.getChildren()) ? 0 : 1);
}
return binaryRoot;
}
private static BinaryTreeNode convertNode(Tree node) {
return node != null ? new BinaryTreeNode(node.getName().toString()) : null;
}
private static BinaryTreeNode convertChildren(List<Tree> children) {
if (children == null || children.isEmpty()) {
return null;
}
BinaryTreeNode root = convertTreeToBinaryTree(children.get(0));
if (children.size() > 1) {
List<Tree> childrenExcludeFirst = new ArrayList<Tree>(children);
childrenExcludeFirst.remove(0);
BinaryTreeNode right = convertChildren(childrenExcludeFirst);
right.setParentId(root.getId());
root.setRight(right);
}
return root;
}
}
2.实体类
/**
* @author YH
* @ClassName BinaryTreeNode.java
* @Description TODO
* @createTime 2022年05月24日 17:13:00
*/
@Data
public class BinaryTreeNode {
private String id;
private String name;
private String parentId;
private int isChildren = 0;
private BinaryTreeNode left;
private BinaryTreeNode right;
public BinaryTreeNode(String name) {
super();
this.name = name;
}
}
实际用法
public static Map<String,Object> head(List<Tree<String>> treeList) throws IOException {
//测试代码,随便看看
Map<String,Object> map = new HashMap<>();
if (CollectionUtils.isEmpty(treeList)){
return null;
}
for (Tree<String> stringTree : treeList) {
BinaryTreeNode binaryTreeNode = BTreeUtil.convertTreeToBinaryTree(stringTree);
beforeRootTraver(binaryTreeNode);
System.out.println("--");
System.out.println();
}
return map;
}
/**
* 用于得到二叉树前序序遍历的结果
*/
public static void beforeRootTraver(BinaryTreeNode root)
{
if(root!=null)
{
System.out.print(root.getName()+root.getId()+root.getIsChildren()+" ");
beforeRootTraver(root.getLeft());
beforeRootTraver(root.getRight());
}
}
/**
* 用于得到二叉树中序遍历的结果
*/
public static void inRootTraver(BinaryTreeNode root)
{
if(root!=null)
{
inRootTraver(root.getLeft());
System.out.print(root.getName()+root.getId()+root.getIsChildren()+" ");
inRootTraver(root.getRight());
}
}
/**
* 用于得到二叉树后序遍历的结果(Node root)
*/
public static void postRootTraver(BinaryTreeNode root)
{
if(root!=null)
{
postRootTraver(root.getLeft());
postRootTraver(root.getRight());
System.out.print(root.getName()+root.getId()+root.getIsChildren()+" ");
}
}
另外附一份普通树的遍历代码(免得以后找了)
/**
* @param tree 开始节点 遍历完之后,org变成新的树
* @param treeList 该节点的子节点集合
* 因为集合是引用数据类型(传递引用地址) 这里void即可,原来的集合是本身就会改变的
* @author Marder
* 遍历树形List,添加一些补充信息
*/
private static void getTree(Tree<String> tree, List<Tree<String>> treeList) {
//开始节点 id作为下一个节点的 父id
String parentId = tree.getId();
//子集合
List<Tree<String>> childs = new ArrayList<>();
//创建集合的迭代器。循环时list的remove会抛异常,故必须用迭代器遍历,调它的remove
Iterator<Tree<String>> iterator = treeList.iterator();
//开始遍历集合
while (iterator.hasNext()) {
//集合中的一个元素
Tree<String> entity = iterator.next();
//该节点的子节点
List<Tree<String>> nextChilds = entity.getChildren();
// 初始节点的parentId是null/0
//if(entity.getParentId()==null || entity.getParentId() == parentId){
if ("0".equals(entity.getParentId()) || entity.getParentId() == parentId) {
//子节点
Tree<String> newEntity = new Tree<String>();
newEntity.setId(entity.getId());
newEntity.setName(entity.getName());
newEntity.setParentId(entity.getParentId());
//该(子)节点的子节点 在entity这个实体类中叫list属性-_-||
newEntity.setChildren(nextChilds);
System.out.println(newEntity.getName() + newEntity.getId());
childs.add(newEntity);
}
}
//设置子节点集合
tree.setChildren(childs);
//给子节点设置它的子节点
//当子节点不为空时
if (!CollectionUtils.isEmpty(childs)) {
//为子节点添加子节点
Iterator<Tree<String>> iterator2 = childs.iterator();
while (iterator2.hasNext()) {
Tree<String> next = iterator2.next();
//且子节点的子节点集合不为空时,递归
if (!CollectionUtils.isEmpty(next.getChildren())) {
getTree(next, next.getChildren());
}
}
}
}
二.导出表头工具类(未优化版本)
import cn.hutool.core.lang.tree.Tree;
import com.google.common.collect.Lists;
import com.huaxin.planned.domain.BinaryTreeNode;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import java.io.IOException;
import java.util.*;
/**
* @author YH
* @Description TODO 导出表头工具类(未优化版本)
* @ClassName BTreeUtil.java
* @createTime 2022年05月24日 17:15:00
*/
public class ExcelDataUtil {
public static Map<String, Object> head(List<Tree<String>> treeList) throws IOException {
//工具变量
Map<String, Object> tempMap = new HashMap<>();
Map<Integer, String> levelMap = new HashMap<>();
Map<String, Object> tableHeadMap = new HashMap<>();
String tempName = "";
//返回体
Map<String, Object> map = new HashMap<>();
if (CollectionUtils.isEmpty(treeList)) {
return null;
}
List<Long> ids = new LinkedList<>();
//[0]作深度,[1]作临时变量,[2]作深度临时变量,[3]作计算变量
int[] deep = new int[5];
for (int i : deep) {
deep[i] = 0;
}
List<List<String>> headTitles = Lists.newArrayList();
for (Tree<String> stringTree : treeList) {
BinaryTreeNode binaryTreeNode = BTreeUtil.convertTreeToBinaryTree(stringTree);
beforeGetIdsAndCount(binaryTreeNode, ids, deep, tempMap);
deep[0] = deep[0] > deep[2] ? deep[0] : deep[2];
deep[2] = 0;
deep[3] = 0;
//算完一个得重置,避免脏数据
tempMap = new HashMap<>();
}
//这里清空公用map避免脏数据
//根据树的深度,开始算层级
for (int i = 0; i <= deep[0]; i++) {
levelMap.put(i, null);
}
for (int i : deep) {
deep[i] = 0;
}
for (Tree<String> stringTree : treeList) {
BinaryTreeNode binaryTreeNode = BTreeUtil.convertTreeToBinaryTree(stringTree);
beforeGetTableHead(binaryTreeNode, headTitles, deep, levelMap, tempMap);
deep[1] = 0;
//算完一个得重置,避免脏数据
tempMap = new HashMap<>();
}
map.put("head", headTitles);
map.put("ids", ids);
return map;
}
/**
* 用于得到二叉树前序遍历拿到深度和ids.
*/
public static void beforeGetIdsAndCount(BinaryTreeNode root, List<Long> ids, int[] deep, Map<String, Object> idsAndCountMap) {
if (root != null) {
System.out.print(root.getName() + root.getId() + root.getIsChildren() + " ");
//获取到 ids值
if (root.getIsChildren() == 0) {
ids.add(Long.valueOf(root.getId()));
}
/**
* 左有右空 层级+1
* 左空右右 同层级
* 左右都空 同级算完上层级置空
*/
BinaryTreeNode left = root.getLeft();
BinaryTreeNode right = root.getRight();
//同步当前层级
Object temp = idsAndCountMap.get(root.getId());
if (temp != null) {
deep[3] = (int) temp;
}
//当有左不为空时,进入层级+1
if (left != null) {
deep[3] = Math.addExact(deep[3], 1);
}
//当右不为空时,加入到同级临时map中去
if (right != null){
if (left != null){
idsAndCountMap.put(right.getId(), deep[3]-1);
}else{
idsAndCountMap.put(right.getId(), deep[3]);
}
}
deep[2] = deep[2] >deep[3] ? deep[2] : deep[3];
beforeGetIdsAndCount(left, ids, deep, idsAndCountMap);
beforeGetIdsAndCount(right, ids, deep, idsAndCountMap);
}
}
/**
* 用于得到二叉树前序遍历拿表头
*/
public static void beforeGetTableHead(BinaryTreeNode root, List<List<String>> headTitles, int[] deep, Map<Integer, String> levelMap, Map<String, Object> tempMap) {
if (root != null) {
//判断是否是上次平级数据
Object temp = tempMap.get(root.getId());
if (temp != null) {
deep[1] = (int) temp;
}
BinaryTreeNode left = root.getLeft();
BinaryTreeNode right = root.getRight();
//赋当前层级的名称
levelMap.put(deep[1], root.getName());
//当有左不为空时,进入层级+1
if (left != null) {
deep[1] = Math.addExact(deep[1], 1);
}
//当右不为空时,加入到同级临时map中去
if (right != null){
if (left != null){
tempMap.put(right.getId(), deep[1]-1);
}else{
tempMap.put(right.getId(), deep[1]);
}
}
if (root.getIsChildren() == 0) {
List<String> headTitle = new LinkedList<>();
for (Integer i : levelMap.keySet()) {
String name = levelMap.get(i);
if (StringUtils.isEmpty(name)) {
name = getName(i, levelMap);
}
headTitle.add(name);
}
headTitles.add(headTitle);
}
if (left==null&&right ==null){
for (Integer i : levelMap.keySet()) {
if (i>=deep[1]-1){
levelMap.put(i, null);
}
}
}
beforeGetTableHead(left, headTitles, deep, levelMap, tempMap);
beforeGetTableHead(right, headTitles, deep, levelMap, tempMap);
}
}
private static String getName(int i, Map<Integer, String> levelMap) {
if (i < 0) {
return null;
}
String name = levelMap.get(i - 1);
if (StringUtils.isEmpty(name)) {
name = getName(i - 1, levelMap);
}
return name;
}
}