java遞歸處理單位人員組織機(jī)構(gòu)樹方式
什么是遞歸?
在說遞歸之前先說說棧(Stack)是什么?
一、棧(Stack)實(shí)現(xiàn)了一個(gè)后進(jìn)先出(LIFO)的數(shù)據(jù)結(jié)構(gòu)。你可以把棧理解為對(duì)象的垂直分布的棧,當(dāng)你添加一個(gè)新元素時(shí),就將新元素放在其他元素的頂部。
二、當(dāng)你從棧中取元素的時(shí)候,就從棧頂取一個(gè)元素。換句話說,最后進(jìn)棧的元素最先被取出,而遞歸算法就是利用了棧的線性結(jié)構(gòu)實(shí)現(xiàn)的。
一、遞歸算法是一種直接或間接地調(diào)用自身的算法。在計(jì)算機(jī)編寫程序中,遞歸算法對(duì)解決一大類問題是十分有效的,它往往使算法的描述簡潔而且易于理解,還可以可以把復(fù)雜的事情變得簡單。
二、遞歸算法是把問題轉(zhuǎn)化為規(guī)模縮小了的同類問題的子問題,然后遞歸調(diào)用函數(shù)(或過程)來表示問題的解。一個(gè)過程(或函數(shù))直接或間接調(diào)用自己本身,這種過程(或函數(shù))叫遞歸過程(或函數(shù))。
三、遞歸過程一般通過函數(shù)或子過程來實(shí)現(xiàn)。遞歸方法:在函數(shù)或子過程的內(nèi)部,直接或者間接地調(diào)用自己的算法。遞歸其實(shí)就是在棧內(nèi)存中不斷的加載同一個(gè)函數(shù)。
什么時(shí)候用遞歸呢?
當(dāng)一個(gè)功能被重復(fù)使用,而每一次使用該功能時(shí)的參數(shù)不確定,都由上次的功能元素結(jié)果來確定。
遞歸的注意事項(xiàng)!
一、必須有可最終達(dá)到的終止條件,否則程序?qū)⑾萑霟o窮循環(huán)出現(xiàn)棧內(nèi)2.存溢出錯(cuò)誤(StackOverflowError);
二、子問題在規(guī)模上比原問題小,或更接近終止條件;
三、子問題可通過再次遞歸調(diào)用求解或因滿足終止條件而直接求解;
四、子問題的解應(yīng)能組合為整個(gè)問題的解。
第一步首先封裝組織部門數(shù)據(jù)
public static List<Map<String, Object>> parseTree(List<Map<String, Object>> list) { List<Map<String, Object>> deptTreeList = new ArrayList<Map<String, Object>>(); // 拼裝好的deptTreeList Map<String, Object> f_idMap = new HashMap<String, Object>(); for (int i = 0, l = list.size(); i < l; i++) { f_idMap.put(String.valueOf(list.get(i).get("F_ID")), list.get(i)); } for (int i = 0, l = list.size(); i < l; i++) { Map<String, Object> map = list.get(i); //f_idMap存儲(chǔ)的均為F_ID為key的鍵值對(duì),如果以F_PID為key可以取出對(duì)象,則表明該元素是父級(jí)元素 if(f_idMap.get(map.get("F_PID")) != null && (map.get("F_ID") != map.get("F_PID"))){ //給當(dāng)前這個(gè)父級(jí)map對(duì)象中添加key為deptList的ArrayList if ((f_idMap.get(map.get("F_PID")) != null) && ((Map<String, Object>) f_idMap.get(map.get("F_PID"))).get("deptList") == null) { ( (Map<String,Object>) f_idMap.get(map.get("F_PID")) ).put("deptList", new ArrayList<Map<String, Object>>()); } Map<String, Object> tmap = (Map<String, Object>) f_idMap.get(map.get("F_PID")); ArrayList<Map<String, Object>> tArrayList = (ArrayList<Map<String, Object>>) tmap.get("deptList"); tArrayList.add(list.get(i)); //處理沒有父節(jié)點(diǎn) } else { deptTreeList.add(list.get(i)); } } return deptTreeList; }
第二步寫Controller調(diào)用
如果不理解就多debug幾次看程序是如何執(zhí)行的。
@Controller @RequestMapping("/dept") public class DeptTreeController { //TODO 獲取帶人員組織部門樹形結(jié)構(gòu) @PostMapping("/getTreeDeptUser") public XmlServiceResult getTreeDeptUser() { XmlServiceResult result = new XmlServiceResult(); List<Map<String, Object>> treeDeptList = new ArrayList(); try (XmlServiceContext context = new XmlServiceContext()) { //獲取單位集合(這個(gè)數(shù)據(jù)就是數(shù)據(jù)庫查出來的,框架不同換成自己數(shù)據(jù)源就好) List deptList = DataUtil.getDataList(context, "sys_dept/getDeptList", "list"); //拼裝單位樹形結(jié)構(gòu) treeDeptList = DataUtil.parseTree(deptList); //獲取用戶集合(這個(gè)數(shù)據(jù)就是數(shù)據(jù)庫查出來的,框架不同換成自己數(shù)據(jù)源就好) List userList = DataUtil.getDataList(context, "sys_user/getUserList", "userList"); // 將單位樹和用戶集合調(diào)用tree方法進(jìn)行遞歸拼裝 tree(treeDeptList, userList); result.getData().put("deptList", treeDeptList); } return result; } /*遞歸遍歷組織機(jī)構(gòu),判斷id相同填入數(shù)據(jù)*/ public void tree(List<Map<String, Object>> deptListTree, List<Map<String, Object>> userList) { for (int i = 0; i < deptListTree.size(); i++) { Map <String,Object> deptMap = deptListTree.get(i); if (!CollectionUtils.isEmpty((List) deptMap.get("deptList"))) { List<Map<String, Object>> deptChildren = (List<Map<String, Object>>) deptMap.get("deptList"); // 封裝有子節(jié)點(diǎn)單位的數(shù)據(jù) List users =new ArrayList(); for (Map userMap : userList) { if (deptMap.get("SID").equals(userMap.get("R_DEPT"))) { // 單位id(SID)和用戶表中的單位id(R_DEPT)對(duì)應(yīng)上則拼裝 users.add(userMap); } } deptListTree.get(i).put("userList",users); tree(deptChildren, userList); // 如果能夠拿到單位集合說明下級(jí)還有單位則遞歸下級(jí)單位list } else { // 封裝沒有子節(jié)點(diǎn)單位數(shù)據(jù) List users =new ArrayList(); for (Map userMap : userList) { if (deptMap.get("SID").equals(userMap.get("R_DEPT"))) { users.add(userMap); } } deptListTree.get(i).put("userList",users); } } } }
第三步打開postman測(cè)試一下成果
下面總結(jié)一下遞歸的優(yōu)缺點(diǎn)
遞歸好處:
- 代碼更簡潔清晰,可讀性更好
- 遞歸可讀性好這一點(diǎn),對(duì)于初學(xué)者可能會(huì)反對(duì)。實(shí)際上遞歸的代碼更清晰,但是從學(xué)習(xí)的角度要理解遞歸真正發(fā)生的什么,是如何調(diào)用的,調(diào)用層次和路線,調(diào)用堆棧中保存了什么,可能是不容易。但是不可否認(rèn)遞歸的代碼更簡潔。
- 一般來說,一個(gè)人可能很容易的寫出前中后序的二叉樹遍歷的遞歸算法,要寫出相應(yīng)的非遞歸算法就比較考驗(yàn)水平了,恐怕至少一半的人搞不定。所以說遞歸代碼更簡潔明了。
遞歸壞處:
- 由于遞歸需要系統(tǒng)堆棧,所以空間消耗要比非遞歸代碼要大很多。
- 而且,如果遞歸深度太大,可能系統(tǒng)撐不住,所以在遞歸之前要考慮數(shù)據(jù)層級(jí)深度否則就棧內(nèi)存溢出(StackOverflowError)。
最后
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
基于FLink實(shí)現(xiàn)實(shí)時(shí)安全檢測(cè)的示例代碼
這篇文章主要為大家詳細(xì)介紹了如何基于FLink實(shí)現(xiàn)實(shí)時(shí)安全檢測(cè)的功能,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,感興趣的可以了解一下2023-02-02mybatis攔截器實(shí)現(xiàn)通用權(quán)限字段添加的方法
這篇文章主要給大家介紹了關(guān)于mybatis攔截器實(shí)現(xiàn)通用權(quán)限字段添加的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用mybatis具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09Java二叉搜索樹遍歷操作詳解【前序、中序、后序、層次、廣度優(yōu)先遍歷】
這篇文章主要介紹了Java二叉搜索樹遍歷操作,結(jié)合實(shí)例形式詳細(xì)分析了Java二叉搜索樹前序、中序、后序、層次、廣度優(yōu)先遍歷等相關(guān)原理與操作技巧,需要的朋友可以參考下2020-03-03Java?C++題解leetcode1441用棧操作構(gòu)建數(shù)組示例
這篇文章主要為大家介紹了Java?C++題解leetcode1441用棧操作構(gòu)建數(shù)組示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-10-10javax.persistence中@Column定義字段類型方式
這篇文章主要介紹了javax.persistence中@Column定義字段類型方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11Spring+Mybatis 實(shí)現(xiàn)aop數(shù)據(jù)庫讀寫分離與多數(shù)據(jù)庫源配置操作
這篇文章主要介紹了Spring+Mybatis 實(shí)現(xiàn)aop數(shù)據(jù)庫讀寫分離與多數(shù)據(jù)庫源配置操作,需要的朋友可以參考下2017-09-09idea使用war以及war exploded的區(qū)別說明
本文詳細(xì)解析了war與warexploded兩種部署方式的差異及步驟,war方式是先打包成war包,再部署到服務(wù)器上;warexploded方式是直接把文件夾、class文件等移到Tomcat上部署,支持熱部署,開發(fā)時(shí)常用,文章分別列出了warexploded模式和war包形式的具體操作步驟2024-10-10簡化API提升開發(fā)效率RestTemplate與HttpClient?OkHttp關(guān)系詳解
這篇文章主要為大家介紹了簡化API,提升開發(fā)效率,RestTemplate與HttpClient?OkHttp關(guān)系介紹,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10使用Vue+Spring Boot實(shí)現(xiàn)Excel上傳功能
這篇文章主要介紹了使用Vue+Spring Boot實(shí)現(xiàn)Excel上傳,需要的朋友可以參考下2018-11-11