【工作问题】多叉树的应用:用户代理等级升级策略

本文介绍了如何使用多叉树数据结构来构建用户等级系统,从低等级到高等级逐级升级。通过从底向上遍历树结构,可以方便地实现用户业绩和社区等级的升级。同时,提出利用贪心算法或动态规划,预先缓存节点业绩,减少高层节点的递归计算,提高效率。
摘要由CSDN通过智能技术生成
前言

还是项目的新需求:每天进行一次更新用户等级,具体等级要求如下:
在这里插入图片描述
很明显的是,高等级用户依赖于低等级用户的业绩和社区等级进行升级。也就是说需要从低等级用户开始升级,层层递进到高等级用户。这个时候选择一个合适的数据结构在开发中能省很多功夫,比如多叉树。

多叉树实现

其实不管是初始化树还是遍历的思路跟二叉树都是一样的。

树的节点:

@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class UserTreeNode {
    private String userId;
    private String parentId;
    private List<UserTreeNode> hierarchy;

}
public class UserTreeUtil {

    /**
     * 返回层级结构树
     */
    public static List<UserTreeNode> getStructure(List<UserTreeNode> allList, List<UserTreeNode> topList) {
        //设置子数据
        if (!CollectionUtils.isEmpty(topList)) {
            for (UserTreeNode entity : topList) {
                //存放结构树字段
                entity.setHierarchy(getChild(entity.getUserId(), allList));
            }
        }
        return topList;
    }

    /**
     * 调用递归
     */
    private static List<UserTreeNode> getChild(String id, List<UserTreeNode> allList) {
        // 子数据
        List<UserTreeNode> childList = Lists.newArrayList();
        for (UserTreeNode entity : allList) {
            // 将父id与传过来的id比较
            if (StringUtils.isNotBlank(entity.getParentId())) {
                if (entity.getParentId().equals(id)) {
                    childList.add(entity);
                }
            }
        }
        // 子级循环
        for (UserTreeNode entity : childList) {
            if (StringUtils.isNotBlank(entity.getParentId())) {
                // 递归
                entity.setHierarchy(getChild(entity.getUserId(), allList));
            }
        }
        // 递归退出
        if (childList.size() == 0) {
            return null;
        }
        return childList;
    }

    /**
     * 获取根节点
     */
    public static List<UserTreeNode> getRootNode(List<UserInfo> userInfoList) {
        List<UserTreeNode> userTreeNodes = new ArrayList<>();
        for (UserInfo userInfo : userInfoList) {
            if (userInfo.getPid() == null) {
                userTreeNodes.add(new UserTreeNode()
                        .setUserId(userInfo.getId().toString())
                        .setParentId(userInfo.getPid() == null ? null : userInfo.getPid().toString()));
            }
        }
        return userTreeNodes;
    }

    /**
     * 获取所有节点
     */
    public static List<UserTreeNode> getAllNode(List<UserInfo> userInfoList) {
        List<UserTreeNode> allUserList = new LinkedList<>();
        userInfoList.forEach(node -> allUserList.add(new UserTreeNode()
                .setUserId(node.getId().toString())
                .setParentId(node.getPid() == null ? null : node.getPid().toString())));
        return allUserList;
    }

    /**
     * 从底向上遍历用户ID树
     *
     * @param root 树根节点
     * @return 从底向上遍历后的用户ID树
     */
    public static List<String> levelOrderBottom(UserTreeNode root) {
        LinkedList<List<String>> res = new LinkedList<>();
        List<String> userTree = new LinkedList<>();
        if (root == null) {
            return userTree;
        }
        UserTreeNode treeNode = root;
        Queue<UserTreeNode> queue = new LinkedList<>();
        queue.offer(treeNode);
        while (!queue.isEmpty()) {
            int size = queue.size();
            List<String> temp = new LinkedList<>();
            while (size > 0) {
                treeNode = queue.poll();
                if (treeNode != null) {
                    temp.add(treeNode.getUserId());
                    if (treeNode.getHierarchy() != null) {
                        for (UserTreeNode userTreeNode : treeNode.getHierarchy()) {
                            queue.offer(userTreeNode);
                        }
                    }
                }
                size--;
            }
            res.addFirst(temp);
        }
        for (List<String> re : res) {
            userTree.addAll(re);
        }
        return userTree;
    }

    /**
     * 遍历节点添加入childTree中
     *
     * @param userTreeNodeList 循环遍历的childList
     * @param childTree        待添加的list
     */
    public static void parseTree(List<UserTreeNode> userTreeNodeList, List<String> childTree) {
        for (UserTreeNode userTreeNode : userTreeNodeList) {
            childTree.add(userTreeNode.getUserId());
            if (userTreeNode.getHierarchy() != null) {
                parseTree(userTreeNode.getHierarchy(), childTree);
            }
        }
    }

    /**
     * 遍历所有该节点的子节点并添加入list内
     *
     * @param userId           最顶节点
     * @param userTreeNodeList user树
     * @return 子树
     */
    public static List<String> loopTree(Long userId, List<UserTreeNode> userTreeNodeList, List<String> childTree) {
        for (UserTreeNode userTreeNode : userTreeNodeList) {
            if (userTreeNode.getUserId().equals(userId.toString()) && userTreeNode.getHierarchy() != null) {
                parseTree(userTreeNode.getHierarchy(), childTree);
            } else {
                if (userTreeNode.getHierarchy() != null) {
                    loopTree(userId, userTreeNode.getHierarchy(), childTree);
                }
            }
        }
        return childTree;
    }
}

实现

有了从底向上遍历后的多叉树list,就可以很方便的进行需求开发。

只要从头遍历这个list,就可以实现从子到父的升级了。

同时为了减少高层节点不必要的递归次数,可以在遍历低层次节点的同时把该节点的业绩和社区等级结果缓存在一个矩阵里(也就是贪心算法或者动态规划)方便高层节点直接取出或进行累加。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值