Java中的什么場景使用遞歸,如何使用遞歸
什么是遞歸?
程序調(diào)用自身的編程技巧叫做遞歸。
遞歸有什么優(yōu)點(diǎn)?
遞歸算法:代碼簡潔、清晰,并且容易驗(yàn)證正確性。在一定的程度上還能幫我們減少很多重復(fù)代碼。
迭代和遞歸的區(qū)別
迭代是逐漸逼近,用新值覆蓋舊值,直到滿足條件后結(jié)束,不保存中間值,空間利用率高。
遞歸是將一個(gè)問題分解為若干相對小一點(diǎn)的問題,遇到遞歸出口再原路返回,因此必須保存相關(guān)的中間值,這些中間值壓入棧保存,問題規(guī)模較大時(shí)會(huì)占用大量內(nèi)存。
遞歸的三個(gè)條件
- 邊界條件
- 遞歸前進(jìn)段
- 遞歸返回段
當(dāng)邊界條件不滿足時(shí),遞歸前進(jìn);當(dāng)邊界條件滿足時(shí),遞歸返回。
什么場景下適合使用遞歸
場景一
項(xiàng)目當(dāng)中菜單很多都是配置的,并且菜單有時(shí)候都是分好幾級(jí)的,當(dāng)我給他配置最下級(jí)的時(shí)候,那么我還得把他的上級(jí)保存起來才能用,但是我們又不確定他有幾個(gè)上級(jí),這個(gè)時(shí)候可以采用遞歸調(diào)用。
public void packageParent(Set<String> parentIdSet) { Set<String> parentIdSet1 = new HashSet<>(); for (String parentId : parentIdSet) { MenuOrg menuOrg = new MenuOrg(); Menu menu = menuRepository.findOne(parentId); if (menu == null) { continue; } menuOrg.setMenuId(menu.getMenuId()); menuOrg.setProType(menu.getProType()); menuOrgRepository.save(menuOrg); if (menu.getParentId() != null) { parentIdSet1.add(menu.getParentId()); } } //判斷parentIdSet1是否為空 if(!CommonUtils.isCollectionBlankOrEmpty(parentIdSet1)) { packageParent(parentIdSet1); } }
場景二
計(jì)算5的階乘
public class Test { public static void main(String[] args) { System.out.println(f(5)); } public static int f(int n) { if (1 == n) return 1; else return n * f(n-1); } }
此題中,按照遞歸的三個(gè)條件來分析:
(1)邊界條件:階乘,乘到最后一個(gè)數(shù),即1的時(shí)候,返回1,程序執(zhí)行到底;
(2)遞歸前進(jìn)段:當(dāng)前的參數(shù)不等于1的時(shí)候,繼續(xù)調(diào)用自身;
(3)遞歸返回段:從最大的數(shù)開始乘,如果當(dāng)前參數(shù)是5,那么就是54,即5(5-1),即n*(n-1)
總結(jié)
遞歸中一定有迭代,但是迭代中不一定有遞歸,大部分可以相互轉(zhuǎn)換。
能用迭代的不用遞歸,遞歸調(diào)用函數(shù),計(jì)算有重復(fù),浪費(fèi)空間,并且遞歸太深容易造成堆棧的溢出。
Java 遞歸算法
一、概述
Java遞歸:簡單說就是函數(shù)自身直接或間接調(diào)用函數(shù)的本身。
二、應(yīng)用場景
若:一個(gè)功能在被重復(fù)使用,并每次使用時(shí),參與運(yùn)算的結(jié)果和上一次調(diào)用有關(guān),這時(shí)就可以使用遞歸來解決這個(gè)問題。
使用要點(diǎn):
1,遞歸一定明確條件。否則容易棧溢出。
2,注意一下遞歸的次數(shù)。
三、示例
最簡單的遞歸演示
public class recursionDemo { public static void main(String[] args) { show(); } private static void show() { method(); } private static void method() { show(); } }
四、實(shí)際示例
我們都知道 6的二進(jìn)制是110,那么程序是怎么執(zhí)行的呢?
代碼示例:
public static void main(String[] args) { toBin(6); } private static void toBin(int num) { if (num>0){ //取余 System.out.println(num%2); toBin(num/2); } }
運(yùn)行過程:
遞歸演示二:計(jì)算1-5,求和
public static void main(String[] args) { //1-5求和 int sum = getSum(5); System.out.println(sum); } private static int getSum(int num) { int x=9; if (num==1){ return 1; } return num+getSum(num-1); }
程序運(yùn)行圖:
五、遞歸的缺點(diǎn)
在使用遞歸時(shí),一定要考慮遞歸的次數(shù),負(fù)責(zé)很容易造成虛擬機(jī) “棧溢出”。
仍然使用上面的求和代碼,只是這次將求和基數(shù)變?yōu)?90000000,看看結(jié)果如何
public static void main(String[] args) { //1-90000000求和 int sum = getSum(90000000); System.out.println(sum); } private static int getSum(int num) { int x=9; if (num==1){ return 1; } return num+getSum(num-1); }
果然就造成了虛擬機(jī)棧溢出。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java中的動(dòng)態(tài)代理實(shí)現(xiàn)代碼實(shí)例
這篇文章主要介紹了Java中的動(dòng)態(tài)代理實(shí)現(xiàn)代碼實(shí)例,jdk動(dòng)態(tài)代理本質(zhì)上是使用被代理對象的類加載器,通過被代理類實(shí)現(xiàn)的接口在運(yùn)行時(shí)動(dòng)態(tài)構(gòu)造出代理類來增強(qiáng)原始類的功能的方法,需要的朋友可以參考下2023-12-12RocketMQ生產(chǎn)者調(diào)用start發(fā)送消息原理示例
這篇文章主要為大家介紹了RocketMQ生產(chǎn)者調(diào)用start發(fā)送消息原理示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11Spring?Boot中的@EnableAutoConfiguration注解詳解
這篇文章主要介紹了Spring?Boot中的@EnableAutoConfiguration注解詳解,Spring?Boot是一個(gè)非常流行的Java框架,它可以快速創(chuàng)建基于Spring的應(yīng)用程序。Spring?Boot提供了許多自動(dòng)配置功能,使得開發(fā)者可以非常容易地創(chuàng)建一個(gè)可運(yùn)行的應(yīng)用程序,需要的朋友可以參考下2023-08-08Springboot整合SpringSecurity的完整案例詳解
Spring Security是基于Spring生態(tài)圈的,用于提供安全訪問控制解決方案的框架,Spring Security登錄認(rèn)證主要涉及兩個(gè)重要的接口 UserDetailService和UserDetails接口,本文對Springboot整合SpringSecurity過程給大家介紹的非常詳細(xì),需要的朋友參考下吧2024-01-01Java數(shù)據(jù)結(jié)構(gòu)之圖的兩種搜索算法詳解
在很多情況下,我們需要遍歷圖,得到圖的一些性質(zhì)。有關(guān)圖的搜索,最經(jīng)典的算法有深度優(yōu)先搜索和廣度優(yōu)先搜索,接下來我們分別講解這兩種搜索算法,需要的可以參考一下2022-11-11