[树形结构]:通过多个顶点查询完整路径的目录结构

需求背景:

最近在搞数据研发平台,有个搜索相关的需求:用户可以通过Job名做模糊搜索,返回相关结果集,并且要携带出完整的目录结构,研发平台目录结构分四种: 根节点是工作空间,子节点有多层嵌套文件夹,文件夹里面是DAG工作流,工作流里是Job任务;需求是要返回完整的目录结构给前端。

解决方案:

这个问题就很有意思了,首先第一点就是树形结构了,因为是模糊搜索,返回的Job可能会多个,如果遍历的话,可能会出现多个完整目录结构,这时会需要做路径合并,难度很大;我改造了树形结构,下面直接上代码:

SearchNode:

定义当前节点的Key,和父类节点的key,都要保证唯一性;

text字段表示当前Node节点的其他字段,统一放入到Map集合中

children表示当前Node节点的子节点,结构是SearchNode的数组集合;

这里在做toString时直接转成JSON格式,且把Map集合中的数据也解出来,这里有个问题:

因为Map的value是Object类型,我这里是直接用正则匹配出数字类型的,不用加双引号,且如果是Boolean类型则也不加双引号;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class SearchNode {
    private String  key;
    private String  parentKey;
    private Map<String,Object> text;

    private List<SearchNode> children;

    private String regex = "([1-9]\\d*\\.?\\d*)|(0\\.\\d*[1-9])";


    public SearchNode(String key, String parentKey, Map<String,Object> text) {
        this.key = key;
        this.parentKey = parentKey;
        this.text = text;
    }

    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder("{");
        sb.append("\"key\":\"")
                .append(key).append('\"');
        sb.append(",\"parentKey\":\"")
                .append(parentKey).append('\"');
        text.forEach((k,v) -> {
            sb.append(",\"").append(k).append("\":");
            Pattern compile = Pattern.compile(regex);
            Matcher matcher = compile.matcher(v.toString());
            if (matcher.matches()) {
                sb.append(v);
            } else {
                if (v.equals(true) || v.equals(false)) {
                    sb.append(v);
                } else {
                    sb.append("\"").append(v).append("\"");
                }
            }
        });
        sb.append(",\"children\":")
                .append(children);
        sb.append('}');
        return sb.toString();
    }
}

SearchTree:

这里是用递归思想获取树形结构,但是我们的需求背景是要拼接成一个完成的目录结构,而不是多个结构,所以选用Set集合去重思路,把重复的SearchNode干掉

public class SearchTree {

    private HashSet<SearchNode> searchNodeList = new HashSet<>();
    public SearchTree(HashSet<SearchNode> searchNodeList) {
        this.searchNodeList = searchNodeList;
    }

    //建立树形结构
    public HashSet<SearchNode> builTree(){
        HashSet<SearchNode> treeSearchNodes =new  HashSet<SearchNode>();
        for(SearchNode searchNodeNode : getRootNode()) {
            searchNodeNode =buildChilTree(searchNodeNode);
            treeSearchNodes.add(searchNodeNode);
        }
        return treeSearchNodes;
    }

    //递归,建立子树形结构
    private SearchNode buildChilTree(SearchNode pNode){
        List<SearchNode> chilSearchNodes =new  ArrayList<SearchNode>();
        for(SearchNode searchNodeNode : searchNodeList) {
            if(searchNodeNode.getParentKey().equals(pNode.getKey())) {
                chilSearchNodes.add(buildChilTree(searchNodeNode));
            }
        }
        pNode.setChildren(chilSearchNodes);
        return pNode;
    }

    //获取根节点
    private List<SearchNode> getRootNode() {
        List<SearchNode> rootSearchNodeLists =new  ArrayList<SearchNode>();
        for(SearchNode searchNodeNode : searchNodeList) {
            if(searchNodeNode.getParentKey().equals("head")) {
                rootSearchNodeLists.add(searchNodeNode);
            }
        }
        return rootSearchNodeLists;
    }


}

测试结果:

@SpringBootTest
public class SearchNodeTests {

    @Test
    public void contextLoads() {
        HashSet<SearchNode> menuList= new HashSet<>();
        HashMap<String, Object> map1 = new HashMap<>();
        map1.put("local","湖北省");

        HashMap<String, Object> map2 = new HashMap<>();
        map2.put("local","山东省");
        HashMap<String, Object> map3 = new HashMap<>();
        map3.put("local","武汉市");
        HashMap<String, Object> map4 = new HashMap<>();
        map4.put("local","仙桃市");
        HashMap<String, Object> map5 = new HashMap<>();
        map5.put("local","青岛市");
        HashMap<String, Object> map6 = new HashMap<>();
        map6.put("local","武昌区");
        HashMap<String, Object> map7 = new HashMap<>();
        map7.put("local","洪山区");
        HashMap<String, Object> map8 = new HashMap<>();
        map8.put("local","洪山街道");
        /*插入一些数据*/
        menuList.add(new SearchNode("1","head",map1));
        menuList.add(new SearchNode("7","head",map2));
        menuList.add(new SearchNode("2","1",map3));
        menuList.add(new SearchNode("3","1",map4));

        menuList.add(new SearchNode("8","7",map5));
        menuList.add(new SearchNode("4","2",map6));
        menuList.add(new SearchNode("5","2",map7));
        menuList.add(new SearchNode("6","4",map8));

        /*让我们创建树*/
        SearchTree menuTree =new SearchTree(menuList);
        menuList=menuTree.builTree();
        /*转为json看看效果*/
        String jsonOutput= JSON.toJSONString(menuList);
        System.out.println("树状数据:"+menuList.toString());


        System.out.println("树里面所有的id"+ this.list);//获取树里面的所有节点
    }

    List<Menu> children=null;
    //参数1:树结构  参数二:节点id
    public List<Menu> recursion (Menu tree, int node){
        if(tree.getId()==node){     //节点id=需要查询的id
            children = tree.getChildren();  //获取children里面的数据返回
        }else {
            for(Menu bean:tree.getChildren()){     //反之递归children里面的数据
                recursion(bean,node);
            }
        }
        return children;
    }

    List<Long> list = new ArrayList<Long>();//初始化id集合
    //获取树里面的所有节点,调用方法前记得清空list
    public void getAllNode(Menu tree) {
        list.add((long) tree.getId());//添加节点
        if (tree.getChildren() != null) {//判断是否有子节点
            for (Menu bean : tree.getChildren()) {//循环递归子节点
                getAllNode(bean);
            }
        }
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

XuTengRui

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

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

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

打赏作者

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

抵扣说明:

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

余额充值