最常见的树结构,遍历&筛选

一下所有都是基于没有维护节点路径的,如果你维护了treePath,所有的操作都会非常节点

存储:我们以最简单的表设定

  • id               # 节点id
  • name        # 节点名
  • parentId    # 父id

节点对象:

如果有其他的属性,集成这个基础的节点对象就好了。

@Data
public class BaseTreeNode  {
    private Long id;
    private Long parentId;
    private String name;
    private List<BaseTreeNode> child;

}

树的操作

通常树的操作有遍历,搜索,基于封装的概念,我们可以把一些基础操作封装在这个对象种

生成树

/**
  * 节点map k是id v是节点对象
  */
public static BaseTreeNode buildTree(Map<Long, ? extends BaseTreeNode> tree) {
        BaseTreeNode rootV = new BaseTreeNode();
        rootV.setChild(new ArrayList<>());
        tree.forEach((k, v) -> {
            BaseTreeNode pnode = tree.get(v.getParentId());
            if (pnode == null && v.getParentId() != 0) {
                // 垃圾节点
                return;
            }
            if (pnode == null && v.getParentId() == 0) {
                rootV.getChild().addNode(v);
                return;
            }
            if (CollectionUtils.isEmpty(pnode.getChild())) {
                pnode.setChild(new ArrayList<>());
            }
            pnode.getChild().addNode(v);
        });
        return rootV;
    }

搜索任意节点,并将节点树展示出来

1:匹配到叶子节点,则从根节点展示到叶子节点

2:匹配到非叶节点,则将根节点展示到该子树

如图:查询b2节点,那么应该显示如下黄色的节点

 

/**
     * 匹配节点树
     * @param node
     * @param trees
     * @param query
     * @return
     */
    public static BaseTreeNode matchQuery(BaseTreeNode node, List<BaseTreeNode> trees, String query) {
        List<BaseTreeNode> matchNodes = new ArrayList<>();
        // 获取匹配的节点
        matchNode(node, matchNodes, query);
        // 深拷贝
        final List<BaseTreeNode> baseTreeNodes = JSONObject.parseArray(JSONObject.toJSONString(trees), BaseTreeNode.class);
        final Map<Long, BaseTreeNode> map = baseTreeNodes.stream().collect(Collectors.toMap(BaseTreeNode::getId, Function.identity()));
        BaseTreeNode root = new BaseTreeNode();
        for (BaseTreeNode n : matchNodes) {
            root = traceRoot(n, map);
        }
        return root;
    }

    private static void matchNode(BaseTreeNode node, List<BaseTreeNode> trees, String query) {
        if (node == null) {
            return;
        }
        if (node.getName().contains(query)) {
            trees.add(node);
            return;
        }
        if (CollectionUtils.isNotEmpty(node.getChild())) {
            node.getChild().forEach(n -> {
                matchNode(n, trees, query);
            });
        }
    }

    public static BaseTreeNode traceRoot(BaseTreeNode node, Map<Long, ? extends BaseTreeNode> tree) {
        final Long pid = node.getParentId();
        if (pid == null || pid == 0) {
            return node;
        }
        final BaseTreeNode pnode = tree.get(pid);
        if (CollectionUtils.isEmpty(pnode.getChild())) {
            pnode.setChild(new BaseTreeList());
        }
        pnode.getChild().add(node);
        return traceRoot(pnode, tree);
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值