蜜桃av色欲a片精品一区,麻豆aⅴ精品无码一区二区,亚洲人成网站在线播放影院在线,亚洲 素人 字幕 在线 最新

微立頂科技

新聞資訊

創(chuàng)新 服務(wù) 價值

  遞歸的改進算法:尾遞歸

發(fā)布日期:2022/8/4 7:23:19      瀏覽量:

執(zhí)行遞歸算法,特別是遞歸執(zhí)行層數(shù)多的時候,結(jié)果極其的慢,并且遞歸層數(shù)達到必定的值,還可能出現(xiàn)內(nèi)存溢出的狀況。本文就要將為你解釋緣由和對應(yīng)的解決方案。算法

1、遞歸與循環(huán)

1.1 所謂的遞歸慢究竟是什么緣由呢?

你們都知道遞歸的實現(xiàn)是經(jīng)過調(diào)用函數(shù)自己,函數(shù)調(diào)用的時候,每次調(diào)用時要作地址保存,參數(shù)傳遞等,這是經(jīng)過一個遞歸工做棧實現(xiàn)的。具體是每次調(diào)用函數(shù)自己要保存的內(nèi)容包括:局部變量、形參、調(diào)用函數(shù)地址、返回值。那么,若是遞歸調(diào)用N次,就要分配N局部變量、N形參、N調(diào)用函數(shù)地址、N返回值,這勢必是影響效率的,同時,這也是內(nèi)存溢出的緣由,由于積累了大量的中間變量沒法釋放。函數(shù)

1.2 用循環(huán)效率會比遞歸效率高嗎?

遞歸與循環(huán)是兩種不一樣的解決問題的典型思路。固然也并非說循環(huán)效率就必定比遞歸高,遞歸和循環(huán)是兩碼事,遞歸帶有棧操做,循環(huán)則不必定,兩個概念不是一個層次,不一樣場景作不一樣的嘗試。性能

1.3 那么遞歸使用的棧是什么樣的一個棧呢?

首先,看一下系統(tǒng)棧和用戶棧的用途。優(yōu)化

2.1 遞歸算法:

優(yōu)勢:代碼簡潔、清晰,而且容易驗證正確性。(若是你真的理解了算法的話,不然你更暈)ui

缺點:它的運行須要較屢次數(shù)的函數(shù)調(diào)用,若是調(diào)用層數(shù)比較深,須要增長額外的堆棧處理(還有可能出現(xiàn)堆棧溢出的狀況),好比參數(shù)傳遞須要壓棧等操做,會對執(zhí)行效率有必定影響??墒牵瑢τ谀承﹩栴},若是不使用遞歸,那將是極端難看的代碼。操作系統(tǒng)

2.2 循環(huán)算法:

優(yōu)勢:速度快,結(jié)構(gòu)簡單。code

缺點:并不能解決全部的問題。有的問題適合使用遞歸而不是循環(huán)。若是使用循環(huán)并不困難的話,最好使用循環(huán)。排序

2.3 遞歸算法和循環(huán)算法總結(jié):

1) 通常遞歸調(diào)用能夠處理的算法,也能夠經(jīng)過循環(huán)去解決,常須要額外的低效處理。遞歸

2)如今的編譯器在優(yōu)化后,對于屢次調(diào)用的函數(shù)處理會有很是好的效率優(yōu)化,效率未必低于循環(huán)。進程

3) 遞歸和循環(huán)二者徹底能夠互換。若是用到遞歸的地方能夠很方便使用循環(huán)替換,而不影響程序的閱讀,那么替換成遞歸每每是好的。(例如:求階乘的遞歸實現(xiàn)與循環(huán)實現(xiàn)。)

3.1 系統(tǒng)棧(也叫核心棧、內(nèi)核棧)

是內(nèi)存中屬于操做系統(tǒng)空間的一塊區(qū)域,其主要用途為:
1)保存中斷現(xiàn)場,對于嵌套中斷,被中斷程序的現(xiàn)場信息依次壓入系統(tǒng)棧,中斷返回時逆序彈出;
2)保存操做系統(tǒng)子程序間相互調(diào)用的參數(shù)、返回值、返回點以及子程序(函數(shù))的局部變量。

3.2 用戶棧

是用戶進程空間中的一塊區(qū)域,用于保存用戶進程的子程序間相互調(diào)用的參數(shù)、返回值、返回點以及子程序(函數(shù))的局部變量。

咱們編寫的遞歸程序?qū)儆谟脩舫绦?,所以使用的是用戶?!?

2、遞歸與尾遞歸

以上初略介紹了遞歸與循環(huán)的實現(xiàn)機理,彷佛代碼簡潔和效率不能共存。那么有沒有一種方法能擁有遞歸代碼簡潔的好處,同時給咱們帶來更快的速率么?算法的世界會告訴你,一切皆有可能。它的名字叫作尾遞歸。

讓遞歸和尾遞歸來作一個對比吧。

2.1 遞歸

用線性遞歸實現(xiàn)Fibonacci函數(shù),程序以下所示:

int FibonacciRecursive(int n) { if( n < 2) return n; return (FibonacciRecursive(n-1)+FibonacciRecursive(n-2));
}

遞歸寫的代碼很是容易懂,徹底是根據(jù)函數(shù)的條件進行選擇計算機步驟。例如如今要計算n=5時的值,遞歸調(diào)用過程以下圖所示,能夠看出,程序向下遞歸,向上返回,因此每一步都須要存儲中間變量和過程。

2.2 尾遞歸

顧名思義,尾遞歸就是從最后開始計算, 每遞歸一次就算出相應(yīng)的結(jié)果, 也就是說, 函數(shù)調(diào)用出如今調(diào)用者函數(shù)的尾部, 由于是尾部, 因此根本沒有必要去保存任何局部變量。直接讓被調(diào)用的函數(shù)返回時越過調(diào)用者, 返回到調(diào)用者的調(diào)用者去。尾遞歸就是把當前的運算結(jié)果(或路徑)放在參數(shù)里傳給下層函數(shù),深層函數(shù)所面對的不是愈來愈簡單的問題,而是愈來愈復(fù)雜的問題,由于參數(shù)里帶有前面若干步的運算路徑。

尾遞歸是極其重要的,不用尾遞歸,函數(shù)的堆棧耗用難以估量,須要保存不少中間函數(shù)的堆棧。好比f(n, sum) = f(n-1) + value(n) + sum,會保存n個函數(shù)調(diào)用堆棧,而使用尾遞歸f(n, sum) = f(n-1, sum+value(n)),這樣則只保留后一個函數(shù)堆棧便可。

采用尾遞歸實現(xiàn)Fibonacci函數(shù),程序以下所示:

int FibonacciTailRecursive(int n,int ret1,int ret2) { if(n==0) return ret1; return FibonacciTailRecursive(n-1,ret2,ret1+ret2);
}

例如如今要計算n=5時的值,尾遞歸調(diào)用過程以下圖所示:

從圖能夠看出,尾遞歸不須要向上返回了,可是須要引入額外的兩個空間來保持當前的結(jié)果,這樣減小了中間變量的存儲和返回,大大提高了效率,并且避免了內(nèi)存溢出。

3、觸類旁通

相信不少讀者對于快速排序都耳熟能詳,不知道各位還記得快速排序的實現(xiàn)就是基于遞歸實現(xiàn)的么,因而這里就提供了一種優(yōu)化快速排序的方案,固然尾遞歸不能改變快速排序的時間復(fù)雜度,可是提高性能仍是沒問題的。筆者再也不作詳細介紹,只貼上實現(xiàn)代碼,留給各位獨立思考的空間。

int Partition(int *p,int len,int start,int last)  
{ int flag=*(p+start); int i=start; int j=last; while(i<j)  
    { while(i<j && *(p+j)>flag) --j;  
        *(p+i)=*(p+j); while(i<j  && *(p+i)<=flag) ++i;  
        *(p+j)=*(p+i);  
    }  
    *(p+i)=flag; return i;     
}  
  
void QuickSort(int *p,int len,int start,int last)  
{ if(NULL=p) return; int index; while(start<last)  
   { index=Partition(p,len,start,last);  
 
     QuickSort(p,len,start,index-1); //QuickSort(p,len,index+1,last);   /**遞歸調(diào)用*/
     start=index+1;   /**尾遞歸調(diào)用*/
   }          
}


  業(yè)務(wù)實施流程

需求調(diào)研 →

團隊組建和動員 →

數(shù)據(jù)初始化 →

調(diào)試完善 →

解決方案和選型 →

硬件網(wǎng)絡(luò)部署 →

系統(tǒng)部署試運行 →

系統(tǒng)正式上線 →

合作協(xié)議

系統(tǒng)開發(fā)/整合

制作文檔和員工培訓

售后服務(wù)

馬上咨詢: 如果您有業(yè)務(wù)方面的問題或者需求,歡迎您咨詢!我們帶來的不僅僅是技術(shù),還有行業(yè)經(jīng)驗積累。
QQ: 39764417/308460098     Phone: 13 9800 1 9844 / 135 6887 9550     聯(lián)系人:石先生/雷先生