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


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

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

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

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

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

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

    1. Map<String,Tree> treeMap = new HashMap<String, Tree>();
    2. Map<String, List<String>> pidMap = new HashMap>();
    3. for (Map<String, Object> map : nodeList) {
    4. //1、我要拿到顶层节点
    5. Object pId = map.get("pId");
    6. String pid = null;
    7. if(pId != null){
    8. pid = pId.toString();
    9. }else{
    10. continue;
    11. }
    12. //2、通过父类id能拿到全部子类的id
    13. if(pidMap.get(pid) == null){
    14. List<String> list = new ArrayList<String>();
    15. list.add(map.get("_id").toString());
    16. pidMap.put(pId.toString(), list);
    17. }else{
    18. List<String> list = pidMap.get(pId.toString());
    19. list.add(map.get("_id").toString());
    20. }
    21. Tree t = new Tree();
    22. t.setParentId(map.get("pId").toString());
    23. t.setName(map.get("name").toString());
    24. t.setId(map.get("_id").toString());
    25. treeMap.put(map.get("_id").toString(), t);
    26. }
    27. List<String> fatherId = new ArrayList<String>(pidMap.keySet());
    28. fatherId.remove("0"); //0代表的是顶级目录的pid,我后面遍历fatherId获得相应的实体类,但是顶级pid是没有相应的实体类的,所以要移除,否则会报null
    29. int size = fatherId.size();
    30. int ii = 0; //我用来做测试,循环多少次
    31. return getTree(fatherId, nodeList.get(0).get("_id").toString(), treeMap, pidMap, new ArrayList<Tree>(), size, ii);
    • 1

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

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

    1. private static List<Tree> getTree(List<String> fatherId, String id, Map<String,Tree> treeMap, Map<String, List<String>> pidMap, List result,int size,int ii) {
    2. //先去获取当前对象,在把子节点的treeset到children里面去。
    3. Tree tree = treeMap.get(id); //这个tree就是实体类!
    4. if(tree !=null){ //正常情况下不会为空,出现为空的情况都是因为有脏数据造成的
    5. if(tree.getParentId() == null||"0".equals(tree.getParentId())){
    6. //我这里应该保存的是一级对象,子对象都在一级对象里面
    7. if(!result.contains(tree)){
    8. result.add(tree);
    9. }
    10. }
    11. //若是叶子节点就没有必要走下面的遍历
    12. List<String> childList = pidMap.get(id);
    13. if(childList != null){
    14. //以下遍历是为了找出子节点
    15. for(String c : childList){
    16. Tree childTree = treeMap.get(c);
    17. String pid = childTree.getParentId();
    18. if(id.equals(pid)){
    19. List<Tree> childrenList = tree.getChildrenList();
    20. if(!childrenList.contains(childTree)){
    21. childrenList.add(childTree);
    22. }
    23. }
    24. ii++;
    25. }
    26. }
    27. }
    28. if(size <= 0){//结束
    29. return result;
    30. }
    31. int ss = size-1;
    32. result = getTree(fatherId, fatherId.get(ss), treeMap, pidMap, result, ss,ii);
    33. System.out.println("循环了======================" + ii);
    34. return result;
    35. }
    • 1

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

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

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

    1. //若是叶子节点就没有必要走下面的遍历
    2. List<String> childList = pidMap.get(id);
    3. if(childList != null){
    4. //以下遍历是为了找出子节点
    5. for(String c : childList){
    6. Tree childTree = treeMap.get(c);
    7. String pid = childTree.getParentId();
    8. if(id.equals(pid)){
    9. List<Tree> childrenList = tree.getChildrenList();
    10. if(!childrenList.contains(childTree)){
    11. childrenList.add(childTree);
    12. }
    13. }
    14. ii++;
    15. }
    16. }
    • 1

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

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

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

    还有个要注意的地方:

    1. if(!childrenList.contains(childTree)){
    2. childrenList.add(childTree);
    3. }
    • 1

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

    自此关键代码就结束啦!

    1. public class Tree {
    2. /**
    3. * 节点唯一标识
    4. */
    5. private String id;
    6. /**
    7. * 节点名称
    8. */
    9. private String name;
    10. /**
    11. * 所属父节点ID
    12. */
    13. private String parentId;
    14. /**
    15. * 所属父节点对象
    16. */
    17. //private Tree parentObj;
    18. /**
    19. * 所含子节点
    20. */
    21. private List<Tree> childrenList = new ArrayList<Tree>();
    • 1

    就不详细列出来。。。

    完整的代码:

    1. public static List<Tree> getAllNodes2(){
    2. DBCollection collection = GGMongoOperator.getGGBusinessCollection("gg_help_center_v3");//帮助中心表
    3. DBObject query = new BasicDBObject("status",1);
    4. DBObject object = new BasicDBObject("_id",1).append("name", 1).append("pId", 1).append("icon", 1);
    5. DBCursor cursor = collection.find(query, object).sort(new BasicDBObject("add_time",1));
    6. List<Map<String,Object>> nodeList = GGDBCursor.find(cursor);
    7. Map<String,Tree> treeMap = new HashMap<String, Tree>();
    8. Map<String, List<String>> pidMap = new HashMap>();
    9. for (Map<String, Object> map : nodeList) {
    10. //1、我要拿到顶层节点
    11. Object pId = map.get("pId");
    12. String pid = null;
    13. if(pId != null){
    14. pid = pId.toString();
    15. }else{
    16. continue;
    17. }
    18. //2、通过父类id能拿到全部子类的id
    19. if(pidMap.get(pid) == null){
    20. List<String> list = new ArrayList<String>();
    21. list.add(map.get("_id").toString());
    22. pidMap.put(pId.toString(), list);
    23. }else{
    24. List<String> list = pidMap.get(pId.toString());
    25. list.add(map.get("_id").toString());
    26. }
    27. Tree t = new Tree();
    28. t.setParentId(map.get("pId").toString());
    29. t.setName(map.get("name").toString());
    30. t.setId(map.get("_id").toString());
    31. treeMap.put(map.get("_id").toString(), t);
    32. }
    33. List<String> fatherId = new ArrayList<String>(pidMap.keySet());
    34. fatherId.remove("0");
    35. int size = fatherId.size();
    36. int ii = 0;
    37. return getTree(fatherId, nodeList.get(0).get("_id").toString(), treeMap, pidMap, new ArrayList<Tree>(), size, ii);
    38. }
    • 1
    1. private static List<Tree> getTree(List<String> fatherId, String id, Map<String,Tree> treeMap, Map<String, List<String>> pidMap, List result,int size,int ii) {
    2. //先去获取当前对象,在把子节点的treeset到children里面去。
    3. Tree tree = treeMap.get(id); //这个tree就是那个固定的常量!
    4. if(tree !=null){
    5. if(tree.getParentId() == null||"0".equals(tree.getParentId())){
    6. //我这里应该保存的是一级对象,子对象都在一级对象里面
    7. if(!result.contains(tree)){
    8. result.add(tree);
    9. }
    10. }
    11. //若是叶子节点就没有必要走下面的遍历
    12. List<String> childList = pidMap.get(id);
    13. if(childList != null){
    14. //以下遍历是为了找出子节点
    15. for(String c : childList){
    16. Tree childTree = treeMap.get(c);
    17. String pid = childTree.getParentId();
    18. if(id.equals(pid)){
    19. List<Tree> childrenList = tree.getChildrenList();
    20. if(!childrenList.contains(childTree)){
    21. childrenList.add(childTree);
    22. }
    23. }
    24. ii++;
    25. }
    26. }
    27. }
    28. if(size <= 0){//结束
    29. return result;
    30. }
    31. int ss = size-1;
    32. result = getTree(fatherId, fatherId.get(ss), treeMap, pidMap, result, ss,ii);
    33. System.out.println("循环了======================" + ii);
    34. return result;
    35. }
    • 1

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

  • 相关阅读:
    大语言模型量化方法对比:GPTQ、GGUF、AWQ
    云原生游戏第 2 讲:OpenKruiseGame 设计理念详解
    Sql server语句练习
    【数据库】实验五 数据库综合查询|多表查询、聚集函数、orderby、groupby
    python语法之变量名
    项目交付过程中,进度失控的原因有哪些?
    Django视图(二)
    这3点职场社交小心机,建议收藏使用
    ORB-SLAM2 ---- Tracking::TrackReferenceKeyFrame函数
    卫星通讯助力船舶可视化监控:EasyCVR视频汇聚系统新应用
  • 原文地址:https://blog.csdn.net/eeeeety6208/article/details/126565650