1. 遞歸查詢樹tree結構有兩種做法:
第一種,遞歸查詢數據庫結構,
第二種,一次性將數據庫表中的所有數據查出來,然后再遞歸查出來的list集合,
第一種做法適合數據量較少的tree結構,因為要一直查詢數據庫數據量大時速度回相對較慢,所以數據量大時建議使用第二種方法,如圖1所示是一個常見的樹tree結構
圖1
2. 反向遞歸(逆向遞歸)查詢樹tree結構根據關鍵字過濾數據
大家有么有遇到過這個問題:我想要根據關鍵字過濾查詢出相關數據和它的上級結構,得到圖1所示結果,可往往不知道怎么做,查不出上級結構總是得到圖3類似的結構,要解決這個比較常見的問題就要用到反向遞歸的算法,網上我那個網搜不到類似的解決方案,本人一時興趣來了,做了一套遞歸和反遞歸的解決方案,簡單易懂,大家可以相互交流一下
圖2
圖3
3.示例代碼
- /**
- * 說明方法描述:將list轉為樹tree結構
- *
- * @param allRrecords
- * @return
- * @time 2016年5月10日 下午6:00:35
- * @author yangdong
- */
- public List<Record> useListRecordToTree(List<Record> allRrecords) {
- List<Record> listParentRecord = new ArrayList<Record>();
- List<Record> listNotParentRecord = new ArrayList<Record>();
- // 第一步:遍歷allRrecords保存所有數據的uuid用於判斷是不是根節點
- Map<String, String> mapAllUuid = new HashMap<String, String>();
- Map<String, Record> allRecordMap = new HashMap<String, Record>();
- for (Record record : allRrecords) {
- mapAllUuid.put(record.getStr("uuid"), record.getStr("uuid"));
- allRecordMap.put(record.getStr("uuid"), record);
- }
- // 第二步:遍歷allRrecords找出所有的根節點和非根節點
- if (allRrecords != null && allRrecords.size() > 0) {
- for (Record record : allRrecords) {
- if (StringUtil.isBlank(record.getStr("parent_uuid"))
- || !mapAllUuid.containsKey(record.getStr("parent_uuid"))) {
- listParentRecord.add(record);
- } else {
- listNotParentRecord.add(record);
- }
- }
- }
- // 第三步: 遞歸獲取所有子節點
- if (listParentRecord.size() > 0) {
- for (Record record : listParentRecord) {
- // 添加所有子級
- record.set("childs", this.getTreeChildRecord(listNotParentRecord, record.getStr("uuid")));
- }
- }
- return listParentRecord;
- }
- /**
- * 說明方法描述:使list轉換為樹並根據關鍵字和節點名稱過濾
- *
- * @param allRecords 所有節點
- * @param keywords 要過濾的關鍵字
- * @param filterFields 要過濾的字段
- * @return
- * @time 2016年5月19日 下午3:27:32
- * @author yangdong
- */
- public List<Record> useListRecordToTreeByKeywords(List<Record> allRecords, String keywords, String... filterFields) {
- List<Record> listRecord = new ArrayList<Record>();
- Map<String, Record> allRecordMap = new HashMap<String, Record>();
- for (Record record : allRecords) {
- allRecordMap.put(record.getStr("uuid"), record);
- }
- // 遍歷allRrecords找出所有的nodeName和關鍵字keywords相關的數據
- if (allRecords != null && allRecords.size() > 0) {
- if (filterFields.length > 1) {
- for (Record record : allRecords) {
- for (String field : filterFields) {
- // 比較
- if (record.getStr(field).toLowerCase().indexOf(keywords.toLowerCase()) != -1) {
- listRecord.add(record);
- }
- }
- }
- } else {
- for (Record record : allRecords) {
- // 比較
- if (record.getStr(filterFields[0]).toLowerCase().indexOf(keywords.toLowerCase()) != -1) {
- listRecord.add(record);
- }
- }
- }
- }
- // 查找過濾出來的節點和他們的父節點
- listRecord = this.getSelfAndTheirParentRecord(listRecord, new ArrayList<Record>(),
- new HashMap<String, Record>(), allRecordMap);
- // 將過濾出來的數據變成樹tree結構
- listRecord = this.useListRecordToTree(listRecord);
- return listRecord;
- }
- /**
- * 說明方法描述:遞歸查詢子節點
- *
- * @param childList 子節點
- * @param parentUuid 父節點id
- * @return
- * @time 2016年5月10日 下午3:29:35
- * @author yangdong
- */
- private List<Record> getTreeChildRecord(List<Record> childList, String parentUuid) {
- List<Record> listParentRecord = new ArrayList<Record>();
- List<Record> listNotParentRecord = new ArrayList<Record>();
- // 遍歷tmpList,找出所有的根節點和非根節點
- if (childList != null && childList.size() > 0) {
- for (Record record : childList) {
- // 對比找出父節點
- if (StringUtil.equals(record.getStr("parent_uuid"), parentUuid)) {
- listParentRecord.add(record);
- } else {
- listNotParentRecord.add(record);
- }
- }
- }
- // 查詢子節點
- if (listParentRecord.size() > 0) {
- for (Record record : listParentRecord) {
- // 遞歸查詢子節點
- record.set("childs", getTreeChildRecord(listNotParentRecord, record.getStr("uuid")));
- }
- }
- return listParentRecord;
- }
- /**
- * 說明方法描述:遞歸找出本節點和他們的父節點
- *
- * @param parentList 根據關鍵字過濾出來的相關節點的父節點
- * @param resultList 返回的過濾出來的節點
- * @param filterRecordMap 已經過濾出來的節點
- * @param allRecordMap 所有節點
- * @return
- * @time 2016年5月19日 上午9:53:56
- * @author yangdong
- */
- private List<Record> getSelfAndTheirParentRecord(List<Record> parentList, List<Record> resultList,
- Map<String, Record> filterRecordMap,
- Map<String, Record> allRecordMap) {
- // 當父節點為null或者節點數量為0時返回結果,退出遞歸
- if (parentList == null || parentList.size() == 0) {
- return resultList;
- }
- // 重新創建父節點集合
- List<Record> listParentRecord = new ArrayList<Record>();
- // 遍歷已經過濾出來的節點
- for (Record record : parentList) {
- String uuid = record.getStr("uuid");
- String parent_uuid = record.getStr("parent_uuid");
- // 如果已經過濾出來的節點不存在則添加到list中
- if (!filterRecordMap.containsKey(uuid)) {
- listParentRecord.add(record);// 添加到父節點中
- filterRecordMap.put(uuid, record);// 添加到已過濾的map中
- allRecordMap.remove(uuid);// 移除集合中相應的元素
- resultList.add(record);// 添加到結果集中
- }
- // 找出本節點的父節點並添加到listParentRecord父節點集合中,並移除集合中相應的元素
- if (StringUtil.isNotBlank(parent_uuid)) {
- Record parentRecord = allRecordMap.get(parent_uuid);
- if (parentRecord != null) {
- listParentRecord.add(parentRecord);
- allRecordMap.remove(parent_uuid);
- }
- }
- }
- // 遞歸調用
- getSelfAndTheirParentRecord(listParentRecord, resultList, filterRecordMap, allRecordMap);
- return resultList;
- }
- //示例
- /**
- * 說明方法描述:遞歸查詢所有權限
- *
- * @param keyword
- * @param is_deleted
- * @return
- * @time 2016年5月10日 下午3:47:50
- * @author yangdong
- */
- public List<Record> getRecordByKeywordRecursive(String keyword, String is_deleted) {
- // 第一步:查詢所有的數據
- StringBuffer sql = new StringBuffer(
- " select pa.uuid,pa.parent_uuid,pa.author_code,pa.author_name,pa.is_menu,pa.sort_number,pa.is_enable,pa.menu_icon ");
- sql.append(" from s_author pa");
- List<Object> params = new ArrayList<Object>();
- sql.append(" where pa.is_deleted=? ");
- params.add(is_deleted);
- sql.append(" order by pa.sort_number asc ");
- List<Record> allRrecords = Db.use(AppConst.DB_DATASOURCE_MAIN).find(sql.toString(), ParamUtil.listToArray(params));
- //第二步:將list變為樹tree結構
- if (StringUtil.isNotBlank(keyword)) {
- return super.useListRecordToTreeByKeywords(allRrecords, keyword, "author_name");
- } else {
- return super.useListRecordToTree(allRrecords);
- }
- }