用递归算法得到Java的树形结构

要求:得到无限分类的菜单栏。并且告诉你任何一个节点,都能得到整个菜单。

用递归算法得到Java的树形结构_第1张图片

数据库是mongodb。没有贴全部,只贴部分。
首先一个整体思路是:
1、要有一个能通过父类id得到全部子类id的集合。
2、遍历这些子类集合来把它们的关系关联起来。

代码部分:
建立数据库的查询:

DBCollection collection = GGMongoOperator.getGGBusinessCollection("gg_help_center_v3");//帮助中心表
    DBObject query = new BasicDBObject("status",1);
    DBObject object = new BasicDBObject("_id",1).append("name", 1).append("pId", 1).append("icon", 1);
    DBCursor cursor = collection.find(query, object).sort(new BasicDBObject("add_time",1));
    List> nodeList = GGDBCursor.find(cursor);

其中List> nodeList = GGDBCursor.find(cursor);
是我公司自己封装的方法。不使用的话,就是用while循环自己来组装数据。
得到的数据格式 key value;比如:
map.put(“_id”,1);
map.put(“name”,”每日头条”)
list.add(map);

之后就是为思路1做准备。紧接着上面的代码:

Map<String,Tree> treeMap = new HashMap<String, Tree>();
Map<String, List<String>> pidMap = new HashMap<String, List<String>>();

    for (Map<String, Object> map : nodeList) {
            //1、我要拿到顶层节点
            Object pId = map.get("pId");
            String pid = null;
            if(pId != null){
                pid = pId.toString();
        }else{
                continue;
        }
        //2、通过父类id能拿到全部子类的id
        if(pidMap.get(pid) == null){
            List<String> list = new ArrayList<String>();
            list.add(map.get("_id").toString());
            pidMap.put(pId.toString(), list);
        }else{
            List<String> list = pidMap.get(pId.toString());
            list.add(map.get("_id").toString());
        }

        Tree t = new Tree();
        t.setParentId(map.get("pId").toString());
        t.setName(map.get("name").toString());
        t.setId(map.get("_id").toString());
        treeMap.put(map.get("_id").toString(), t);
    }
    List<String> fatherId = new ArrayList<String>(pidMap.keySet());
    fatherId.remove("0"); //0代表的是顶级目录的pid,我后面遍历fatherId获得相应的实体类,但是顶级pid是没有相应的实体类的,所以要移除,否则会报null
    int size = fatherId.size();
    int ii = 0; //我用来做测试,循环多少次
return getTree(fatherId, nodeList.get(0).get("_id").toString(), treeMap, pidMap, new ArrayList<Tree>(), size, ii);

上面的代码中pidMap就是思路1中所说的集合,通过父类id,得到全部的子类id。
treeMap:保存的就是所有数据的实体类。格式是:key:_id, value:实体类。
Tree:这个是我自己定义的pojo类。
属性有:id,name,parentId,List<Tree> childrenList = new ArrayList<Tree>();

getTree(…)这个方法就是思路2中去遍历各个子类集合中把它们的关系关联起来。
代码如下:

private static List<Tree> getTree(List<String> fatherId, String id, Map<String,Tree> treeMap, Map<String, List<String>> pidMap, List<Tree> result,int size,int ii) {
        //先去获取当前对象,在把子节点的treeset到children里面去。
        Tree tree = treeMap.get(id); //这个tree就是实体类!
        if(tree !=null){ //正常情况下不会为空,出现为空的情况都是因为有脏数据造成的
            if(tree.getParentId() == null||"0".equals(tree.getParentId())){
                //我这里应该保存的是一级对象,子对象都在一级对象里面
                if(!result.contains(tree)){
                    result.add(tree);
                }
            }

            //若是叶子节点就没有必要走下面的遍历
            List<String> childList = pidMap.get(id);
            if(childList != null){
                //以下遍历是为了找出子节点
                for(String c : childList){
                    Tree childTree = treeMap.get(c);
                    String pid = childTree.getParentId();
                    if(id.equals(pid)){
                        List<Tree> childrenList = tree.getChildrenList();
                        if(!childrenList.contains(childTree)){
                            childrenList.add(childTree);
                        }
                    }
                    ii++;
                }
            }
        }

        if(size <= 0){//结束
            return result;
        }
int ss = size-1;    
result = getTree(fatherId, fatherId.get(ss), treeMap, pidMap, result, ss,ii);
System.out.println("循环了======================" + ii);
return result;

    }

详解————这里我使用了递归:

if(tree.getParentId() == null||"0".equals(tree.getParentId())){
        //我这里应该保存的是一级对象,子对象都在一级对象childrenList里面
        if(!result.contains(tree)){
            result.add(tree);
        }
}

这段代码的意思就是当它是顶级节点时就加入result。我这么写是假设它有多个顶级节点。一般情况下就一个。↑

        //若是叶子节点就没有必要走下面的遍历
        List<String> childList = pidMap.get(id);
        if(childList != null){
            //以下遍历是为了找出子节点
            for(String c : childList){
                Tree childTree = treeMap.get(c);
                String pid = childTree.getParentId();
                if(id.equals(pid)){
                    List<Tree> childrenList = tree.getChildrenList();
                    if(!childrenList.contains(childTree)){
                        childrenList.add(childTree);
                    }
                }
                ii++;
            }
        }

这个遍历就是去遍历子类节点集合把它们都添加到父类的childrenList中去。↑

        if(size <= 0){//结束
            return result;
        }
        int ss = size-1;

    result = getTree(fatherId, fatherId.get(ss), treeMap, pidMap, result, ss,ii);
        System.out.println("循环了======================" + ii);
        return result;

这块代码是进行递归的关键。每次递归时,我都从fatherId中取一个id。
fatherId保存的是所有具有子类的id集合,也就是说,叶子节点不在里面,在里面的都是有子类的;↑

还有个要注意的地方:

if(!childrenList.contains(childTree)){
    childrenList.add(childTree);
}

这里使用contains是因为childTree是个list数组,不会去重。若不去重,就会造成重复数据。↑

自此关键代码就结束啦!

public class Tree {

    /**
     * 节点唯一标识
     */
    private String id;

    /**
     * 节点名称
     */
    private String name;

    /**
     * 所属父节点ID
     */
    private String parentId;

    /**
     * 所属父节点对象
     */
    //private Tree parentObj;

    /**
     * 所含子节点
     */
    private List childrenList = new ArrayList();

就不详细列出来。。。

完整的代码:

    public static List<Tree> getAllNodes2(){
        DBCollection collection = GGMongoOperator.getGGBusinessCollection("gg_help_center_v3");//帮助中心表
        DBObject query = new BasicDBObject("status",1);
        DBObject object = new BasicDBObject("_id",1).append("name", 1).append("pId", 1).append("icon", 1);
        DBCursor cursor = collection.find(query, object).sort(new BasicDBObject("add_time",1));
        List<Map<String,Object>> nodeList = GGDBCursor.find(cursor);

        Map<String,Tree> treeMap = new HashMap<String, Tree>();
        Map<String, List<String>> pidMap = new HashMap<String, List<String>>();

        for (Map<String, Object> map : nodeList) {
            //1、我要拿到顶层节点
            Object pId = map.get("pId");
            String pid = null;
            if(pId != null){
                pid = pId.toString();
            }else{
                continue;
            }
            //2、通过父类id能拿到全部子类的id
            if(pidMap.get(pid) == null){
                List<String> list = new ArrayList<String>();
                list.add(map.get("_id").toString());
                pidMap.put(pId.toString(), list);
            }else{
                List<String> list = pidMap.get(pId.toString());
                list.add(map.get("_id").toString());
            }

            Tree t = new Tree();
            t.setParentId(map.get("pId").toString());
            t.setName(map.get("name").toString());
            t.setId(map.get("_id").toString());
            treeMap.put(map.get("_id").toString(), t);
        }
        List<String> fatherId = new ArrayList<String>(pidMap.keySet());
        fatherId.remove("0");
        int size = fatherId.size();
        int ii = 0;
        return getTree(fatherId, nodeList.get(0).get("_id").toString(), treeMap, pidMap, new ArrayList<Tree>(), size, ii);

    }
    private static List<Tree> getTree(List<String> fatherId, String id, Map<String,Tree> treeMap, Map<String, List<String>> pidMap, List<Tree> result,int size,int ii) {
        //先去获取当前对象,在把子节点的treeset到children里面去。

        Tree tree = treeMap.get(id); //这个tree就是那个固定的常量!
        if(tree !=null){
            if(tree.getParentId() == null||"0".equals(tree.getParentId())){
                //我这里应该保存的是一级对象,子对象都在一级对象里面
                if(!result.contains(tree)){
                    result.add(tree);
                }
            }

            //若是叶子节点就没有必要走下面的遍历
            List<String> childList = pidMap.get(id);
            if(childList != null){
                //以下遍历是为了找出子节点
                for(String c : childList){
                    Tree childTree = treeMap.get(c);
                    String pid = childTree.getParentId();
                    if(id.equals(pid)){
                        List<Tree> childrenList = tree.getChildrenList();
                        if(!childrenList.contains(childTree)){
                            childrenList.add(childTree);
                        }
                    }
                    ii++;
                }
            }
        }
        if(size <= 0){//结束
            return result;
        }
        int ss = size-1;

        result = getTree(fatherId, fatherId.get(ss), treeMap, pidMap, result, ss,ii);
        System.out.println("循环了======================" + ii);
        return result;

    }

再加上Tree这个pojo类,就OK啦!

你可能感兴趣的:(mongodb,Java,专业知识)