普通树转二叉树(普通树为Hutool工具类)

本文分两段.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;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值