树结构的层级遍历

本文介绍了如何遍历树结构的标签数据,从JSON转换为Java类并利用递归和广度优先搜索算法来获取所有节点信息。通过优化,实现了按层次分离节点,方便查找特定层级的标签。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近遇到了需要解析标签树的问题,具体的场景是,有如下结构的标签树:

全球购----国际奢品----时装

     |          |

     |          ----男士精选

     |          |

     |          ----箱包

     |

     ----时尚潮牌----I.T

     |          |

     |          ----Topshop

     |          |

     |          ----ASOS

     |

     ---海外百货----苹果配件

     |          |

     |          ----童装

     |          |

     |          ----玩具

     |

     ---热门代购----2012

               |

               ----劲爆打折

               |

               ----果冻鞋

 

数据通过json的形式返回,json中的每个标签结点包含标签自身的信息,以及子标签的数组,为了方便使用,首先通过Gson将得到的json数据转化为java类CatPathDO

public class CatPathDO{
    private CatPathDO[] subCats;
    private boolean isBright;
    private boolean isVirtual;
    private String name;
    private long tagId;
}

但是这样的结构,如果想要获取所有叶子节点的数据,或者给定一个节点的id,要得到这个节点的所有子节点,却不是那么方便,于是就想能否通过一次遍历,将这些节点的信息都取出来放入一个一维的容器中,只要传入节点id或者name,就能获得这个节点以及它的子节点的信息。

 

最开始是用递归的方法,将每个节点和它的子节点放到一个Map中:

public void buildMapFromCatPath(CatPathDO root,Map<String,CatPathDO[]> catMap){
       
       if(root.getSubCats()!=null){
           for(CatPathDO subCatDO : root.getSubCats()){
              buildMapFromCatPath(subCatDO,catMap);
           }
           catMap.put(root.getName(), root.getSubCats());
       }
       
    }

后来基于广度优先算法的启发,又写了一个基于队列的方法,只需要遍历一次树中的节点,可以避免递归过深的堆栈调用问题:

public void buildMapFromCatPath2(CatPathDO root,Map<String,CatPathDO[]> catMap){
       
       Queue<CatPathDO> queue = new LinkedList<CatPathDO>();
       queue.offer(root);
       while(queue.size()>0){
           CatPathDO node = queue.poll();
//         System.out.println(node.getName());
           CatPathDO[] subCats = node.getSubCats();
           if(subCats!=null){
              for(CatPathDO chileNode : subCats){
                  queue.offer(chileNode);
              }
              catMap.put(node.getName(),subCats);
           }
       }
       
    }

两种方法的效果是一样的,最后catMap中的内容打印出来的如下:

 

热门代购--->

   2012春夏

   劲爆打折

   果冻鞋

   时髦墨镜

   人字拖

   明星同款

   polo衫

时尚潮牌--->

   I.T

   Topshop

   ASOS

   Juicy

   大嘴猴

   潮款T恤

   牛仔很忙

   热力印花

   复古波点

   PUNK范儿

全球购--->

   国际奢品

   时尚潮牌

   海外百货

   热门代购

海外百货--->

   苹果配件

   童装

   玩具

   户外装备

   奶粉

   香水

   美妆护肤

国际奢品--->

   大牌时装

   男士精选

   箱包

   鞋履

   高级珠宝

   腕表

   Chanel

   Prada

   LV

    Burberry

但是这种方式还是不能将每个层级的标签结点单独提取出来,要将每层的结点分开,必须自己记录一下树结构每层的结点数量,并判断该层的结点是否已经遍历完毕。版本3的方法将版本2的Queue该为了一个List结构,并通过变量next来标识该层结点的结束位置下标(即将该层结点全部加入list之后list的大小),偏移量current来表示当前需要处理的结点,实现将每层的标签分离。

public void buildMapFromCatPath3(CatPathDO root,Map<String,List<CatPathDO>> catMap){
       
       List<CatPathDO> nodeList = new ArrayList<CatPathDO>();
       int current = 0;
         
       int next = 0;
       int level = 1;
       nodeList.add(root);
       while(current < nodeList.size()){
           next = nodeList.size();
           List<CatPathDO> nodeInLevel = new ArrayList<CatPathDO>();
           while(current < next){
              CatPathDO currentNode = nodeList.get(current);
              nodeInLevel.add(currentNode);
//            System.out.print(currentNode.getName()+"|");
              CatPathDO[] childNodes = currentNode.getSubCats();
              if(childNodes != null&&childNodes.length > 0){
                  for(CatPathDO node : childNodes){
                     nodeList.add(node);
                  }
              }
              current++;
           }
           catMap.put("Level:"+level, nodeInLevel);
           level++;
//         System.out.println("\n");
       }
       
    }

Level:2--->

   国际奢品

   时尚潮牌

   海外百货

   热门代购

Level:3--->

   大牌时装

   男士精选

   箱包

   鞋履

   高级珠宝

   腕表

   Chanel

   Prada

   LV

   Burberry

   I.T

   Topshop

   ASOS

   Juicy

   大嘴猴

   潮款T恤

   牛仔很忙

   热力印花

   复古波点

   PUNK范儿

   苹果配件

   童装

   玩具

   户外装备

   奶粉

   香水

   美妆护肤

   2012春夏

   劲爆打折

   果冻鞋

   时髦墨镜

   人字拖

   明星同款

   polo衫

Level:1--->

    全球购


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值