前言
树形结构是项目开发中常常用到的一种结构,也是一种经典的数据结构,比如说常见的二叉树,红黑树等,今天要说的不是基础的数据结构,是业务中用到的树形数据结构。
正文
先来看看业务是什么吧!
业务
如这张图,上图中的每一个节点都是可以独立发送消息的,而其消息内容就是节点中的条件1和条件2并且加上其所有的祖籍节点的条件信息。怎样遍历整颗树呢?我是通过三层for循环实现的。
实现
先看从数据库中查出的数组的详细情况:
数组中总共有6条数据,每条数据中有当前节点的id对应上图中的serialNumber 和当前节点的父节点pid 对应上图中的hierarchy ,通过遍历这个数组来实现业务中的需求。
代码
private StringBuffer processGraphString(String processGraphId){
StringBuffer stringBuffer=new StringBuffer();
//微服务间调用,查询同一流程画布下的所有的策略器
ItooResult processData= iProcessGraph.queryProcessGraph(processGraphId);
HashMap processMap=(HashMap) processData.getData();
//取出查出的策略器数组
List policyList=(List) processMap.get("policyrRelevanceModelList");
//定义一个新的数组,此数组是最终的一个数组,里边存放策略器数组,存放当前策略器id及当前策略器的所有祖籍策略器id
List listAll=new ArrayList();
if (policyList !=null){
//策略器组合的数组
String temp="";
for (int i = 0; i <policyList.size() ; i++) {
//拿到单个的策略器对象
HashMap policyHashMap=(HashMap) policyList.get(i);
//取出当前策略器对象中的父id
String policyFather=(String) policyHashMap.get("hierarchy");
if (temp.equals("")){
//此树结构中总根节点不在循环遍历的过程中当程序第一次运行时中间变量temp为空,temp存储的是当前策略器的父节点id
temp=policyFather;
//在树的列表中查找出当前策略器节点的所有子节点集合
//policyList 中存储的是一个完整的树结构的数组,也就是总的数组
//policyFather 中存储的是当前策略器的父节点id
List listChild = ergodicList(policyList, policyFather, policyList);
listAll.addAll(listChild);
}else if (!temp.equals(policyFather)) {
List listChild = ergodicList(policyList, policyFather, policyList);
listAll.addAll(listChild);
}
temp=policyFather;
}
}
//循环遍历listAll中的所有策略器id并根据id查询字符串
if (listAll.size()!=0){
for (int i = 0; i < listAll.size(); i++) {
List list=(List) listAll.get(i);
for (int j = 0; j < list.size(); j++) {
HashMap hashMap=(HashMap) list.get(j);
String policyId=(String)hashMap.get("policyCanId");
stringBuffer.append(policyString(policyId));
}
}
}
return stringBuffer;
}
/*
* 功能描述:遍历数组得到新的数组
* [childList]
* @return
*/
private List ergodicList(List childList,String rootNode,List fatherList){
//childList,fatherList是整个完整的树形结构数组
//rootNode是父节点id,每次的值是变化的
//新建的listChild作用待定
//List listChild=new ArrayList();
//要返回的数组,就是传入的rootNode节点的所有的子节点数组
List returnList=new ArrayList();
//循环整个完整的树形结构的数组
for (int i = 0; i <childList.size() ; i++) {
//定义一个新的数组,数组中存的是当前根节点是rootNod节点的所有父节点的策略器和当前的策略器
List newList=new ArrayList();
HashMap processHash=(HashMap)childList.get(i);
//获取当前策略器的hierarchy编号作为父项编号
String hierarchyNum=(String) processHash.get("hierarchy");
//hierachyNum是否与根节点相同如果相同说明 hierarchyNum是根节点的一个子节点,将这个子节点插入到新的数组中
if (rootNode.equals(hierarchyNum)){
//listChild.add(processHash);
//当前策略器本身
newList.add(processHash);
//当前策略器的父节点策略器
//hierarchyNum是当前的策略器的父节点
List list= ergodic(fatherList,hierarchyNum);
newList.addAll(list);
}
if (newList.size() != 0){
returnList.add(newList);
}
}
return returnList;
}
/**
* 功能描述:通过叶子节点找到当前分支上的所有的父节点并存储到一个list
* [fatherList, hierarchyNum]
* @return 当前叶子节点所在分支上的所有父节点
*/
private List ergodic(List fatherList,String hierarchyNum){
//fatherList 是整个树的全部list集合
List newList=new ArrayList();
//将根节点赋值给中间变量temp
String temp=hierarchyNum;
//循环整体的全部list集合
for (int j = 0; j < fatherList.size(); j++) {
//获取当前策略器
HashMap processHashFather=(HashMap)fatherList.get(j);
//获取当前策略器的serialNumber作为比对条件,进行条件的拼接
String serialFatherA=(String) processHashFather.get("serialNumber");
//获取当前策略器的hierarchy编号作为父项编号
String hierarchyNumA=(String) processHashFather.get("hierarchy");
if (hierarchyNum.equals(serialFatherA)){
newList.add(processHashFather);
temp=hierarchyNumA;
}
//让此方法循环找到同一条线上的所有父节点
if (!temp.equals("0") && (j==fatherList.size()-1)){
j=-1;
hierarchyNum=temp;
}
}
return newList;
}
针对于三个for循环的说明:
第一个for循环主要是遍历当前树中的所有的节点。
第二个for循环主要是根据父节点信息找到这个父节点的所有的子节点,并且找到子节点的所有祖籍节点。
第三个for循环整个树,根据当前节点id找到所有的祖籍节点。
当然这个种方法不管是时间复杂的还是空间复杂度都很高。
结束
针对于以上的树形结构遍历的问题,还有其他的设计方案来解决。
在树形结构的维护表中添加一个维护字段,字段的内容为当前节点的所有的祖籍节点。
通过祖籍节点可以得到所有想要的整棵树的信息,而其也比较简单。