java Tree 树状结构递归搜索算法;过滤保留父节点

1 篇文章 0 订阅
1 篇文章 0 订阅

需求是这样的:数据库的数据是类似菜单那种的tree结构,产品想要搜索。 但是通过搜索出来数据就会构建不起一个tree。必须要保留没命中的父节点 。

        初始树
       /**
         *
         *                              1
         *                           /  |  \
         *                          2   3   4
         *                        / \   /\
         *                       5  6  7  8
         *                      /     /\
         *                    11     9 10
         *                   / \
         *                 12  13
         */

如果输入过滤条件 1,3,7,13:输入结果如下

        /**
         *
         *                              1
         *                           /  |
         *                          2   3
         *                        /    /
         *                       5   7
         *                      /
         *                    11
         *                     \
         *                     13
         */

废话少说,直接上代码

package com.jie.mini.controller.rest.sys.tree;

import lombok.Data;

import java.util.List;

/**
 * 树节点
 * @author jie
 * @date 2021/3/9 11:53
 */
@Data
public class Node {

    private Integer id;

    private Integer parentId;

    private List<Node> children;

    public Node(Integer id ,Integer parentId) {
        this.id = id;
        this.parentId = parentId;
    }

    public Node() {
    }
}

 主要是根据isRemoveNode方法判断该节点是个应该删除

package com.jie.mini.controller.rest.sys.tree;

import org.apache.commons.collections.CollectionUtils;

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

/**
 * @author jie
 * @date 2021/3/9 11:54
 */
public class Client {

    public static void main(String[] args) {

        /**
         *
         *                              1
         *                           /  |  \
         *                          2   3   4
         *                        / \   /\
         *                       5  6  7  8
         *                      /     /\
         *                    11     9 10
         *                   / \
         *                 12  13
         */
        // 构建树
        Node tree = initNode();

        // 预设 命中的节点
        List<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(3);
        list.add(7);
        list.add(13);

        Node node = filterTree(tree, list);
        System.out.println(node);
        /**
         *
         *                              1
         *                           /  |
         *                          2   3
         *                        /    /
         *                       5   7
         *                      /
         *                    11
         *                     \
         *                     13
         */
    }

    /**
     * 过滤树
     * @param tree
     * @param list
     * @return
     */
    private static Node filterTree(Node tree, List<Integer> list) {
        if(isRemoveNode(tree, list)){
            return null;
        }
        Iterator<Node> iterator = tree.getChildren().iterator();
        while (iterator.hasNext()){
            Node child = iterator.next();
            deleteNode(child, iterator, list);
        }
        return tree;
    }

    /**
     * 删除节点
     * @param child
     * @param iterator
     * @param list
     */
    private static void deleteNode(Node child, Iterator<Node> iterator, List<Integer> list) {
        if(isRemoveNode(child,list)){
            iterator.remove();
            return;
        }
        List<Node> childrenList = child.getChildren();
        if(CollectionUtils.isEmpty(childrenList)){
            return;
        }
        Iterator<Node> children = childrenList.iterator();
        while (children.hasNext()){
            Node childChild = children.next();
            deleteNode(childChild,children,list);
        }
    }

    /**
     * 判断该节点是否该删除
     * @param root
     * @param list  命中的节点
     * @return ture 需要删除  false 不能被删除
     */
    private static boolean isRemoveNode(Node root, List<Integer> list) {
        List<Node> children = root.getChildren();
        // 叶子节点
        if(CollectionUtils.isEmpty(children)){
            return !list.contains(root.getId());
        }
        // 子节点
        if(list.contains(root.getId())){
            return false;
        }
        // 如果存在一个子节点不能删除,那么就不能删除
        boolean bool = true;
        for (Node child : children) {
            if(!isRemoveNode(child,list)){
                bool = false;
                break;
            }
        }
        return bool;
    }

    /**
     * 初始化树状结构
     *                              1
     *                           /  |  \
     *                          2   3   4
     *                        / \   /\
     *                       5  6  7  8
     *                      /     /\
     *                    11     9 10
     *                   / \
     *                 12  13
     */
    private static Node initNode() {
        Node root = new Node(1,-1);
        List<Node> rootChildren = new ArrayList<>();
        Node node2= new Node(2, 1);
        Node node3= new Node(3, 1);
        Node node4= new Node(4, 1);
        rootChildren.add(node2);
        rootChildren.add(node3);
        rootChildren.add(node4);
        root.setChildren(rootChildren);

        Node node5= new Node(5, 2);
        Node node11= new Node(11, 5);
        List<Node> node5Children = new ArrayList<>();
        node5Children.add(node11);
        node5.setChildren(node5Children);

        Node node12= new Node(12, 11);
        Node node13= new Node(13, 11);
        List<Node> node11Children = new ArrayList<>();
        node11Children.add(node12);
        node11Children.add(node13);
        node11.setChildren(node11Children);

        Node node6= new Node(6, 2);

        List<Node> node2Children = new ArrayList<>();
        node2Children.add(node5);
        node2Children.add(node6);
        node2.setChildren(node2Children);

        Node node7= new Node(7, 2);
        Node node8= new Node(8, 2);

        List<Node> node3Children = new ArrayList<>();
        node3Children.add(node7);
        node3Children.add(node8);
        node3.setChildren(node3Children);

        Node node9= new Node(9, 7);
        Node node10= new Node(10, 7);

        List<Node> node7Children = new ArrayList<>();
        node7Children.add(node9);
        node7Children.add(node10);
        node7.setChildren(node7Children);
        return root;
    }
}

再贴一个开箱即用的工具类;实体实现TreeFilterModel.Node构造树;调用searchNode方法

package com.xxx.sone.admin.api.utils;

import cn.hutool.core.collection.CollectionUtil;
import com.google.common.collect.Lists;

import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author jie
 * @date 2021/3/9 11:54
 */
public class TreeFilterModel<T extends TreeFilterModel.Node>{


    /**
     * 获取树状结构
     * @param treeList搜索的树列表
     * @param hitIds 命中的ids
     * @return
     */
    public List<T> searchNode(List<T> treeList,List<Integer> hitIds) {
       List<T> filterTree = Lists.newArrayList();
        for (T t : treeList) {
            T node = filterTree(t, hitIds);
            filterTree.add(node);
        }
        return filterTree.stream().filter(Objects::nonNull).collect(Collectors.toList());
    }

    /**
     * 过滤树
     * @param tree
     * @param hitIds
     * @return
     */
    private T filterTree(T tree, List<Integer> hitIds) {
        if(isRemoveNode(tree, hitIds)){
            return null;
        }
        Iterator<T> iterator = (Iterator<T>)tree.getNodeChildren().iterator();
        while (iterator.hasNext()){
            T child = iterator.next();
            deleteNode(child, iterator, hitIds);
        }
        return tree;
    }

    /**
     * 删除节点
     * @param child
     * @param iterator
     * @param hitIds
     */
    private void deleteNode(T child, Iterator<T> iterator, List<Integer> hitIds) {
        if(isRemoveNode(child, hitIds)){
            iterator.remove();
            return;
        }
        List<T> childrenList = (List<T>)child.getNodeChildren();
        if(CollectionUtil.isEmpty(childrenList)){
            return;
        }
        Iterator<T> children = childrenList.iterator();
        while (children.hasNext()){
            T childChild = children.next();
            deleteNode(childChild,children, hitIds);
        }
    }

    /**
     * 判断该节点是否该删除
     * @param root
     * @param hitIds  命中的节点
     * @return ture 需要删除  false 不能被删除
     */
    private boolean isRemoveNode(T root, List<Integer> hitIds) {
        List<T> children = (List<T>) root.getNodeChildren();
        // 叶子节点
        if(CollectionUtil.isEmpty(children)){
            return !hitIds.contains(root.getNodeId());
        }
        // 子节点
        if(hitIds.contains(root.getNodeId())){
            return false;
        }
        boolean bool = true;
        for (T child : children) {
            if(!isRemoveNode(child,hitIds)){
                bool = false;
                break;
            }
        }
        return bool;
    }

    public interface Node<T> {
        /**
         * 搜索节点的id
         * @return
         */
        Integer getNodeId();

        /**
         * 字节的列表
         * @return
         */
        List<T> getNodeChildren();
    }
}

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值