两种算法实现树形fullPath设置

前言

当我业务有树形数据结构时候,我们通常设计会预留一个字段叫fullPath. 这个字段保留的是本节点到一级节点路径一般取id + “/”。
比如 id = 1,parentId = 0,fullpath=1;
id=2,parentId=1,fullpath=1/2,id=3,parentId=2,fullpath=1/2/3,之所以设置fullPah 他可以获取快速的获取上级任意节点以及层级,或者在获取断层树形中也有意义。 重点来了今天分享这个适合没有设置过fullPath
但是业务又想使用或者升级数据。两种实现方式第一种就是递归方式,第二种使用Map 和for循环实现各有优势大家需要根据自己业务选择。

实现方案

递归实现

    public static void setFullPathWithRecursion(List<TreeNode> treeNodes, TreeNode rootNode) {
        for (TreeNode treeNode : treeNodes) {
            if (Objects.equals(rootNode.getId(), treeNode.getParentId())) {
                treeNode.setFullPath(rootNode.getFullPath() + "/" + treeNode.getFullPath());
                setFullPathWithRecursion(treeNodes, treeNode);
            }
        }
        return;
    }

Map 和for循环实现

 public static List<TreeNode> setFullPath(List<TreeNode> treeNodeList) {
        Map<BigInteger, BigInteger> rootMap = Maps.newHashMap();
        // 先将id和parentId 放入map
        for (TreeNode node : treeNodeList) {
            if (Objects.isNull(node.getParentId()) || Objects.equals(node.getParentId(), BigInteger.ZERO)) {
                rootMap.put(node.getId(), BigInteger.ZERO);
            } else {
                rootMap.put(node.getId(), node.getParentId());
            }
        }
        for (TreeNode file : treeNodeList) {
            int count = 0;
            BigInteger p = file.getParentId();
            //一级不做处理
            if (Objects.equals(p, BigInteger.ZERO)) {
                continue;
            }
            // 只要没到最后一级就继续遍历, count 是为了有脏数据导致一直循环 消耗资源,根据自己业务设置
            while (!Objects.equals(rootMap.get(p), BigInteger.ZERO) && count < 10) {
                file.setFullPath(p + "/" + file.getFullPath());
                p = rootMap.get(p);
                count++;
            }
            //处理最后一级
            file.setFullPath(p + "/" + file.getFullPath());
        }
        return treeNodeList;
    }

测试

测试代码

    public static void main(String[] args) {
        List<TreeNode> list = Lists.newArrayList();
        TreeNode treeNode = new TreeNode();
        treeNode.setId(new BigInteger("1"));
        treeNode.setParentId(new BigInteger("0"));
        treeNode.setFullPath(String.valueOf(treeNode.getId()));
        list.add(treeNode);
        TreeNode treeNode1 = new TreeNode();
        treeNode1.setId(new BigInteger("2"));
        treeNode1.setParentId(new BigInteger("1"));
        treeNode1.setFullPath(String.valueOf(treeNode1.getId()));
        list.add(treeNode1);

        TreeNode treeNode2 = new TreeNode();
        treeNode2.setId(new BigInteger("3"));
        treeNode2.setParentId(new BigInteger("2"));
        treeNode2.setFullPath(String.valueOf(treeNode2.getId()));

        list.add(treeNode2);
        //count 分别测试100 1000 10000
        int count = 100;
        for (int i = 0; i < count; i++) {
            TreeNode treeNodes = new TreeNode();
            treeNodes.setId(new BigInteger(RandomUtil.randomNumbers(10)));
            treeNodes.setParentId(new BigInteger("1"));
            treeNodes.setFullPath(String.valueOf(treeNodes.getId()));
            list.add(treeNodes);
        }
 StopWatch stopwatch = new StopWatch("Test");
        stopwatch.start("递归获取fullPath任务");
        TreeUtil.setFullPathWithRecursion(list, treeNode);
        stopwatch.stop();
        System.out.println("任务名称:" + stopwatch.getLastTaskName() + "任务量:" + list.size() + " 总耗时:" + stopwatch.getLastTaskTimeMillis() + "ms" + "内存:" + SystemUtil.getRuntimeInfo());
        stopwatch.start("Map获取fullPath任务");
        TreeUtil.setFullPath(list);
        stopwatch.stop();
        System.out.println("任务名称:" + stopwatch.getLastTaskName() + "任务量:" + list.size() + " 总耗时:" + stopwatch.getLastTaskTimeMillis() + "ms" + "内存:" + SystemUtil.getRuntimeInfo());

测试结果

count=100

在这里插入图片描述

count = 1000

在这里插入图片描述

count = 10000

在这里插入图片描述

总结

递归在循环个数一定范围内有时间和内存使用优势,一旦超过临界值,时间就会随着count增大而增加。Map 和for循环实现
基本就是空间换时间。适合count 比较大的场景。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蜗牛乌龟一起走

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值