最近遇到了需要解析标签树的问题,具体的场景是,有如下结构的标签树:
全球购----国际奢品----时装
| |
| ----男士精选
| |
| ----箱包
|
----时尚潮牌----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--->
全球购