JSTree下的模糊查询算法——树结构数据层次遍历和递归分治地深入应用

图片描述

图片描述

A表示区域节点,S表示站点结点

问题描述:现有jstree包含左图中的所有结点信息(包含区域结点和站点结点),需要做到输入站点名称模糊查询,显示查询子树结果如右图

解决策略:

  1、先模糊查询所得站点所在区域结点A5,A6,A4,根据这些从下往上搜索所有子树的区域结点(主义表述,是区域结点),存至set集合(避免重复放入)

  2、找出set集合中的最高点A1(最高点的父节点为空),查询结点信息放入jsonobject,从上往下搜索子树中A1所有孩子结点(A2,A4),递归遍历A2,A4的孩子结点,存至孩子结点数组,

遇到区域结点没有孩子结点则表示其到了最底层区域结点(A5,A6,A4),将其对应区域结点信息存至其孩子结点数组

  3、两步递归操作,设值注入最高点结点信息,最终得到包含整棵子树的所有结点信息。返回给页面


if (name != null && !"".equals(name)) {
    name = new String(name.getBytes("iso-8859-1"),"utf-8"); //字符串转码
    StringBuffer searchValue = new StringBuffer();
    searchValue.append("%").append(name).append("%");      //模糊查询格式化
    List<StationBase> stationBaseList = stationBaseService.findStationBaseByName(searchValue.toString());      //根据站点名称模糊查找站点集合
    List<String> stationCodes = new ArrayList<>();      //装填上面模糊查询中所负责的站点code,
    List<Integer> areaIds_bottom = new ArrayList<>();     //存放上面站点所在区域id,即最底层的区域结点id
    Set<Integer> areaIdSet = new HashSet<Integer>();        //存放子树中所有区域结点的id,避免重复用set集合
    for (StationBase stationBase:stationBaseList) {
        if(areaIds.contains(stationBase.getArea().getId())){    //areaIds表示用户所负责的所有区域站点的id,即整颗树区域节点id
            stationCodes.add(stationBase.getStationCode());
            areaIds_bottom.add(stationBase.getArea().getId());
            areaIdSet.add(stationBase.getArea().getId());
        }
    }
    areaIdSet = getAllAreaIdBySearch(areaIdSet,areaIds_bottom);     //设值注入获取子树中所有区域结点的id
    //找出最高点,装入集合
    JSONObject jo_top = new JSONObject();       //最高点结点
    for(Integer area_Id : areaIdSet){
        if(area_Id!=null){
            List<Integer> area_Ids = new ArrayList<>();     //为了符合传入的是List集合
            area_Ids.add(area_Id);
            if(stationBaseService.findParentIdsByAreaIds(area_Ids).get(0)==null) {      //找出最高点,并装填信息
                Area area = areaService.findAllArea(area_Id).get(0);
                JSONObject state = new JSONObject();
                jo_top.put("id", areaPrefix + area.getId());
                jo_top.put("text", area.getArea());
                jo_top.put("type", "areatype");
                state.put("opened", true);
                jo_top.put("state", state);
                jo_top = findChainArea(jo_top, areaIdSet, areaPrefix, stationCodes);     //设值注入获取包含根结点的子树
                break;
            }
        }
    }
    jsonArray.add(jo_top);      //存入json数组
    return jsonArray;
}
/**
 * 递归查找包括最底层areaIdSet一直往上的所有areaId,避免重复用Set集合
 * @param areaIdSet     最底层到最高层所有层的areaId集合
 * @param areaId_row    根据用户输入站点名所查的最底层areaId集合
 * @return
 */
protected Set<Integer> getAllAreaIdBySearch(Set<Integer> areaIdSet,List<Integer> areaId_row){
    if(areaId_row!=null &amp;&amp; areaId_row.size()>0 &amp;&amp; areaId_row.get(0)!=null){      //areaId_row写在与前面,避免为空先做判断,直到查到ParentId为空结束递归
        List<Integer> areaParentIdList = stationBaseService.findParentIdsByAreaIds(areaId_row);     //获取当前areaId_row所有的parentId
        for (Integer areaId:areaParentIdList){
            areaIdSet.add(areaId);         //使用set集合对所搜集areaId进行去重
        }
        return getAllAreaIdBySearch(areaIdSet,areaParentIdList);    //递归访问上一层区域结点
    }
    return areaIdSet;
}


/**
 * 递归查找从最高点jo往下一层层遍历,将遍历结点存至孩子结点数组中
 * @param jo       最高点
 * @param areaIdSet     整颗树区域id
 * @param areaPrefix    区域id前缀
 * @param stationCodes  子树所有站点code
 * @return
 */
protected JSONObject findChainArea(JSONObject jo,Set<Integer> areaIdSet,String areaPrefix,List<String> stationCodes){
    List<Integer> childIds = stationBaseService.findIdsByParent(Integer.parseInt(jo.get("id").toString().split("_")[1]));
    if(childIds!=null &amp;&amp; childIds.size()>0 &amp;&amp; childIds.get(0)!=null){       //有子区域节点,非叶节点
        //查询子区域节点信息,添加到jo中,areaIdSet中对应的id
        JSONArray areaChildArray = new JSONArray();     //存放该结点在对应子树中的孩子结点数组
        for (Integer childId:childIds) {
            if(areaIdSet.contains(childId)){     //属于子树中结点便添加到孩子结点数组中
                Area area = areaService.findAllArea(childId).get(0);
                JSONObject jo_child = new JSONObject();
                JSONObject state = new JSONObject();
                jo_child.put("id",areaPrefix+area.getId());
                jo_child.put("text",area.getArea());
                jo_child.put("type","areatype");
                state.put("opened", true);
                jo_child.put("state",state);
                jo_child = findChainArea(jo_child,areaIdSet,areaPrefix,stationCodes);
                areaChildArray.add(jo_child);
            }
        }
        jo.put("children",areaChildArray);
    }else{      //无子区域,叶节点,添加站点信息
        List<StationBase> stationBaseList = stationBaseService.findByAreaId(Integer.parseInt(jo.get("id").toString().split("_")[1]));
        JSONArray stationArray = new JSONArray();       //该站点下的所有站点
        for (StationBase stationBase : stationBaseList){
            if(stationCodes.contains(stationBase.getStationCode())){
                JSONObject stationObj = new JSONObject();
                stationObj.put("id", "s_" + stationBase.getStationCode());
                stationObj.put("text", stationBase.getStationName());
                stationObj.put("type", "stationInfo");
                stationObj.put("children", false);
                stationArray.add(stationObj);
            }
        }
        jo.put("children",stationArray);
    }
    return jo;
}