Java实现树数据Tree与List互转并逐级汇总节点的值(支持树节点多列统计)

主要需求:a.实现树Tree与List互转   b.Tree实现多列统计数据汇总。前度采用MiniUI。

逐级汇总数据:找到最小节点,然后回溯其所有父节点,注意值的重复计算问题。

构造一棵树的基本节点:

package com.example.demo.tree;

import java.util.ArrayList;
import java.util.List;

/**
 * @ClassName: TreeNode
 * @Description: TODO(树的节点对象)
 * @author: pengjunlin
 * @motto: 学习需要毅力,那就秀毅力
 * @date 2019-06-18 23:35
 */
public class TreeNode {

    /**
     * 节点ID
     */
    private long id;
    /**
     * 显示名称
     */
    private String label;
    /**
     * 当前节点的唯一值
     */
    private double value;
    /**
     * 当前节点的多个值的表达方式
     */
    private double[] multiValues=new double[]{};
    /**
     * 汇总单个节点的多个值
     */
    private List<Double> values=new ArrayList<Double>();
    /**
     * 当前节点所有子节点的值集合
     */
    private List<double []> childrenMultiValues=new ArrayList<double []>();
    /**
     * 父节点ID
     */
    private long pid;
    /**
     * 子节点集合对象
     */
    private List<TreeNode> children=new ArrayList<TreeNode>();
    /**
     * 是否计算本身
     */
    private boolean addSelf=false;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getLabel() {
        return label;
    }

    public void setLabel(String label) {
        this.label = label;
    }

    public double getValue() {
        return value;
    }

    public void setValue(double value) {
        this.value = value;
    }

    public double[] getMultiValues() {
        return multiValues;
    }

    public void setMultiValues(double[] multiValues) {
        this.multiValues = multiValues;
    }

    public List<Double> getValues() {
        return values;
    }

    public void setValues(List<Double> values) {
        this.values = values;
    }

    public List<double[]> getChildrenMultiValues() {
        return childrenMultiValues;
    }

    public void setChildrenMultiValues(List<double[]> childrenMultiValues) {
        this.childrenMultiValues = childrenMultiValues;
    }

    public long getPid() {
        return pid;
    }

    public void setPid(long pid) {
        this.pid = pid;
    }

    public List<TreeNode> getChildren() {
        return children;
    }

    public void setChildren(List<TreeNode> children) {
        this.children = children;
    }

    public boolean isAddSelf() {
        return addSelf;
    }

    public void setAddSelf(boolean addSelf) {
        this.addSelf = addSelf;
    }
}

构造树管理工具:

package com.example.demo.tree;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
 * @ClassName: TreeManager
 * @Description: TODO(树结构数据管理-实践验证)
 * @author: pengjunlin
 * @motto: 学习需要毅力,那就秀毅力
 * @date 2019-06-18 23:47
 */
public class TreeManager {

    /**
     * 将List转成tree结构数据
     * @param list
     * @param rootId 默认顶级节点ID
     * @return
     */
    public static List<TreeNode> listToTree(List<TreeNode> list,long rootId){
        List<TreeNode> tree=new ArrayList<TreeNode>();
        Map<Long, TreeNode> map = new HashMap<Long, TreeNode>();
        // 将所有的数据,以键值对的形式装入map中
        for (TreeNode node : list) {
            // 去除冗余的子节点
            node.setChildren(new ArrayList<TreeNode>());
            map.put(node.getId(), node);
        }
        for (TreeNode node : list) {
            // 如果id是父级的话就放入tree中
            if (node.getId() == rootId) {
                tree.add(node);
            } else {
                // 子级通过父id获取到父级的类型
                TreeNode parent = map.get(node.getPid());
                // 父级获得子级,再将子级放到对应的父级中
                if(parent!=null){
                    parent.getChildren().add(node);
                }
            }
        }
        return tree;
    }

    /**
     * 将tree结构数据转成List结构
     * @param list
     * @return
     */
    public static void treeToList(TreeNode node,List<TreeNode> list){
        if(list==null){
            list=new ArrayList<TreeNode>();
        }
        //设置当前节点的必要数据
        TreeNode nodeValue=new TreeNode();
        nodeValue.setId(node.getId());
        nodeValue.setLabel(node.getLabel());
        nodeValue.setValue(node.getValue());
        nodeValue.setMultiValues(node.getMultiValues());
        nodeValue.setChildrenMultiValues(node.getChildrenMultiValues());
        nodeValue.setPid(node.getPid());
        nodeValue.setChildren(new ArrayList<TreeNode>());
        list.add(nodeValue);
        //遍历递归子节点
        if(node.getChildren().size()>0){
            for (int i = 0; i < node.getChildren().size(); i++) {
                TreeNode node_= node.getChildren().get(i);
                treeToList(node_,list);
            }
        }
    }

    /**
     * 转换数据格式并设置对应节点的值汇总到根节点
     * @param list
     * @param rootId
     * @return
     */
    public static List<TreeNode> listToTreeWithSingleValue(List<TreeNode> list,long rootId){
        Map<Long, TreeNode> map = new HashMap<Long, TreeNode>();
        // 将所有的数据,以键值对的形式装入map中
        for (TreeNode node : list) {
            // 去除冗余的子节点
            node.setChildren(new ArrayList<TreeNode>());
            map.put(node.getId(), node);
        }
        List<TreeNode> tree=listToTree(list,rootId);
       /* // 存储最小子节点ID
        Map<Long,Object> leafList=new  HashMap<Long,Object>();
        findMinNodes(tree.get(0),leafList,0);
        // 设置每个节点的值
        for (Long id_: leafList.keySet()) {
            // 内部递归树的父节点层级多于2会存在重复计算
            setParentNodeValue(map,id_);
        }*/

        // 存储最小子节点ID
        Map<Long,Object> leaf=new  HashMap<Long,Object>();
        findMinNodes(tree.get(0),leaf);
        // 逐级设置父节点的值
        setValuesToParentNode(leaf, map);

        // 汇总所有节点的值
        double total=0;
        for (TreeNode node:map.values() ) {
            total=0;
            for (double value: node.getValues() ) {
                total+=value;
            }
            node.setValue(total);
            map.put(node.getId(),node);
        }
        List<TreeNode>  result=new ArrayList<TreeNode>();
        for (TreeNode node:map.values()) {
            result.add(node);
        }
        return listToTree(result,rootId);
    }

    /**
     * 转换数据格式并设置对应节点的值汇总到根节点
     * @param tree
     * @return
     */
    public static  List<TreeNode>   treeToListWithSingleValue(TreeNode tree){
        List<TreeNode> list=new ArrayList<TreeNode>();
        // 获取到List
        treeToList(tree,list);
        Map<Long, TreeNode> map = new HashMap<Long, TreeNode>();
        // 将所有的数据,以键值对的形式装入map中
        for (TreeNode node : list) {
            // 去除冗余的子节点
            node.setChildren(new ArrayList<TreeNode>());
            map.put(node.getId(), node);
        }
       /* // 存储最小子节点ID
        Map<Long,Object> leafList=new  HashMap<Long,Object>();
        findMinNodes(tree,leafList,0);
        // 设置每个节点的值
        for (Long id_: leafList.keySet()) {
            // 内部递归树的父节点层级多于2会存在重复计算
            setParentNodeValue(map,id_);
        }*/

        // 存储最小子节点ID
        Map<Long,Object> leaf=new  HashMap<Long,Object>();
        findMinNodes(tree,leaf);
        // 逐级设置父节点的值
        setValuesToParentNode(leaf, map);

        // 汇总所有节点的值
        double total=0;
        for (TreeNode node:map.values() ) {
            total=0;
            for (double value: node.getValues() ) {
                total+=value;
            }
            node.setValue(total);
            map.put(node.getId(),node);
        }
        List<TreeNode>  result=new ArrayList<TreeNode>();
        for (TreeNode node:map.values()) {
            result.add(node);
        }
        return result;
    }

    /**
     * 转换数据格式并设置对应节点的值汇总到根节点
     * @param list
     * @param rootId
     * @param columns
     * @return
     */
    public static List<TreeNode> listToTreeWithMultiValues(List<TreeNode> list,long rootId,int columns){
        Map<Long, TreeNode> map = new HashMap<Long, TreeNode>();
        // 将所有的数据,以键值对的形式装入map中
        for (TreeNode node : list) {
            // 去除冗余的子节点
            node.setChildren(new ArrayList<TreeNode>());
            map.put(node.getId(), node);
        }
        List<TreeNode> tree=listToTree(list,rootId);

       /* // 存储最小子节点ID
        Map<Long,Object> leafList=new  HashMap<Long,Object>();
        findMinNodes(tree.get(0),leafList,0);
        // 设置每个节点的值
        for (Long id_: leafList.keySet()) {
            // 内部递归树的父节点层级多于2会存在重复计算
            setParentNodeMultiValues(map,id_);
        }*/

        // 存储最小子节点ID
        Map<Long,Object> leaf=new  HashMap<Long,Object>();
        findMinNodes(tree.get(0),leaf);
        // 逐级追加父节点的值
        setMultiValuesToParentNode(leaf, map);

        // 汇总所有节点的值
        double [] valueColumns=null;
        for (TreeNode node:map.values() ) {
            valueColumns=new double[columns];
            for (double [] values: node.getChildrenMultiValues() ) {
                for (int i = 0,j=values.length; i < j; i++) {
                    valueColumns[i]+=values[i];
                }
            }
            node.setMultiValues(valueColumns);
            map.put(node.getId(),node);
        }
        List<TreeNode>  result=new ArrayList<TreeNode>();
        for (TreeNode node:map.values()) {
            result.add(node);
        }
        return listToTree(result,rootId);
    }

    /**
     * 转换数据格式并设置对应节点的值汇总到根节点
     * @param tree
     * @param columns
     * @return
     */
    public static  List<TreeNode>  treeToListWithMultiValues(TreeNode tree,int columns){
        List<TreeNode> list=new ArrayList<TreeNode>();
        // 获取到List
        treeToList(tree,list);
        Map<Long, TreeNode> map = new HashMap<Long, TreeNode>();
        // 将所有的数据,以键值对的形式装入map中
        for (TreeNode node : list) {
            // 去除冗余的子节点
            node.setChildren(new ArrayList<TreeNode>());
            map.put(node.getId(), node);
        }
        /*
        // 存储最小子节点ID
        Map<Long,Object> leafList=new  HashMap<Long,Object>();
        findMinNodes(tree,leafList,0);
        // 设置每个节点的值
        for (Long id_: leafList.keySet()) {
             // 内部递归树的父节点层级多于2会存在重复计算
            setParentNodeMultiValues(map,id_);
        }*/

        // 存储最小子节点ID
        Map<Long,Object> leaf=new  HashMap<Long,Object>();
        findMinNodes(tree,leaf);
        // 逐级追加父节点的值
        setMultiValuesToParentNode(leaf, map);

        // 汇总所有节点的值
        double [] valueColumns=null;
        for (TreeNode node:map.values() ) {
            valueColumns=new double[columns];
            for (double [] values: node.getChildrenMultiValues() ) {
                for (int i = 0,j=values.length; i < j; i++) {
                    valueColumns[i]+=values[i];
                }
            }
            node.setMultiValues(valueColumns);
            map.put(node.getId(),node);
        }
        List<TreeNode>  result=new ArrayList<TreeNode>();
        for (TreeNode node:map.values()) {
            result.add(node);
        }
        return result;
    }

    /**
     * 逐级追加设置节点的值(单个值)
     * @param leaf
     * @param map
     */
    public static void setValuesToParentNode(Map<Long,Object> leaf,Map<Long, TreeNode> map){
        Map<Long,Object> newLeaf=new  HashMap<Long,Object>();
        // 设置每个节点的值
        for (Long id_: leaf.keySet()) {
            setParentNodeValue(newLeaf,map,id_);
        }
        if(newLeaf.size()>1){
            setValuesToParentNode(newLeaf, map);
        }
    }

    /**
     * 逐级追加设置节点的值(多个值)
     * @param leaf
     * @param map
     */
    public static void setMultiValuesToParentNode( Map<Long,Object> leaf,Map<Long, TreeNode> map){
        Map<Long,Object> newLeaf=new  HashMap<Long,Object>();
        // 设置每个节点的值
        for (Long id_: leaf.keySet()) {
            setParentNodeMultiValues(newLeaf,map,id_);
        }
        if(newLeaf.size()>1){
            setMultiValuesToParentNode(newLeaf, map);
        }
    }

    /**
     * 数学运算
     * @param mathChar
     * @param dest
     * @param newValue
     */
    public static void mathHandle(String mathChar,double dest,double newValue){
        switch (mathChar) {
            case "+":
                dest+=newValue;
                break;
            case "-":
                dest-=newValue;
                break;
            case "*":
                dest*=newValue;
                break;
            case "/":
                dest/=newValue;
                break;
            default:
                break;
        }
    }

    /**
     * 查找最小子叶节点(没有子节点的节点)
     * @param node
     * @param leafList
     */
    private static void findMinNodes(TreeNode node,Map<Long,Object> leafList){
        if(node.getChildren().size()>0){
            TreeNode nodeTmp=null;
            for (int i = 0; i < node.getChildren().size(); i++) {
                nodeTmp= node.getChildren().get(i);
                findMinNodes(nodeTmp,leafList);
            }
        }else{
            leafList.put(node.getId(),node.getId());
        }
    }

    /**
     * 根据ID逐级查找父节点并设置值(设置单个值逐级递归)
     * @param map
     * @param id
     */
    private static void setParentNodeValue(Map<Long,Object> newLeaf,Map<Long, TreeNode> map,long id){
        TreeNode node=map.get(id);
        // 设置自身节点的值
        if(!node.isAddSelf()){
            node.setAddSelf(true);
            node.getValues().add(node.getValue());
            // 更新节点数据
            map.put(node.getId(),node);
        }
        TreeNode pNode=map.get(node.getPid());
        if(pNode!=null){
            // 将子节点的值赋给父节点
            pNode.getValues().addAll(node.getValues());
            // 设置自身节点的值
            if(!pNode.isAddSelf()){
                pNode.setAddSelf(true);
                pNode.getValues().add(pNode.getValue());
            }
            // 更新节点数据
            map.put(pNode.getId(),pNode);
            //setParentNodeValue(map,pNode.getId());
            newLeaf.put(pNode.getId(), pNode.getId());
        }
    }

    /**
     * 根据ID逐级查找父节点并设置值(设置多个值逐级递归)
     * @param map
     * @param id
     */
    private static void setParentNodeMultiValues(Map<Long,Object> newLeaf,Map<Long, TreeNode> map,long id){
        TreeNode node=map.get(id);
        // 设置自身节点的值
        if(!node.isAddSelf()){
            node.setAddSelf(true);
            node.getChildrenMultiValues().add(node.getMultiValues());
            // 更新节点数据
            map.put(node.getId(),node);
        }
        TreeNode pNode=map.get(node.getPid());
        if(pNode!=null){
            // 将子节点的值赋给父节点
            pNode.getChildrenMultiValues().addAll(node.getChildrenMultiValues());
            // 设置自身节点的值
            if(!pNode.isAddSelf()){
                pNode.setAddSelf(true);
                pNode.getChildrenMultiValues().add(pNode.getMultiValues());
            }
            // 更新节点数据
            map.put(pNode.getId(),pNode);
            //setParentNodeMultiValues(map,pNode.getId());
            newLeaf.put(pNode.getId(), pNode.getId());
        }
    }

    @SuppressWarnings("unused")
    public static void main(String[] args) {
        TreeNode tree=new TreeNode();
        tree.setId(1);
        tree.setLabel("顶层节点");
        tree.setValue(1);
        tree.setChildrenMultiValues(new ArrayList<double []>());
        tree.setPid(0);

        List<TreeNode> list =new ArrayList<TreeNode>();
        TreeNode node1=new TreeNode();
        node1.setId(2);
        node1.setLabel("子节点1");
        node1.setValue(100);
        node1.setMultiValues(new double[]{5,7,3});
        node1.setChildrenMultiValues(new ArrayList<double []>());
        node1.setPid(1);
        list.add(node1);
        TreeNode node2=new TreeNode();
        node2.setId(3);
        node2.setLabel("子节点2");
        node2.setValue(10);
        node2.setMultiValues(new double[]{2,5,8});
        node2.setChildrenMultiValues(new ArrayList<double []>());
        node2.setPid(1);
        list.add(node2);

        tree.setChildren(list);

        List<TreeNode> destList=new ArrayList<TreeNode>();
        TreeManager.treeToList(tree,destList);
        System.out.println("tree转list完成");

        List<TreeNode> treeList=TreeManager.listToTree(destList,1);

        System.out.println("List转tree完成");

        /*******************注意单个值计算结果会影响多个值计算结果**************/

        List<TreeNode> treeListSingleValue=TreeManager.listToTreeWithSingleValue(destList,1);
        System.out.println("List转tree 汇总唯一值value完成");

        List<TreeNode> treeListSingleValue2=TreeManager.treeToListWithSingleValue(tree);
        System.out.println("tree转List 汇总唯一值value完成");

//        List<TreeNode> treeListMultiValues=TreeManager.listToTreeWithMultiValues(destList,1,3);
//        System.out.println("List转tree 汇总多个值values完成");
//
//        List<TreeNode> treeListMultiValues2=TreeManager.treeToListWithMultiValues(tree,3);
//        System.out.println("tree转List 汇总多个值values完成");

    }
}

注:如果数据字段跟工具树的不一致可以使用Map转对象来实现。

Github源码:https://github.com/open-micro-services/springcloud/tree/master/sc-demo-projects/sb-tree

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值