遞迴演算法分析 201805

2021-08-19 21:56:37 字數 3022 閱讀 6719

遞迴演算法

一、定義

若乙個演算法直接或間接地呼叫自己本身,則稱這個演算法為遞迴演算法。

例1:階乘函式遞迴表示:若n=0,f(n)=1;若n>0,f(n)=n*f(n-1);

public int factorialbyrecursion(int n) else if(n==0) 

return factorialbyrecursion(n-1)*n;

}

二、執行過程在例1中,若要求2的階乘2!,即求factorialbyrecursion(2)[簡寫f(2)]。

此時的呼叫過程:首先main函式使用實參n=2呼叫f(2),而f(2)需要呼叫到f(1),f(1)需要呼叫到f(0)。這裡得到f(0)=1,再將f(0)的值返回到前次呼叫f(1)=f(0)*1=1,再返回f(1)的值到f(2)=f(1)*2=2,得到結果f(2)=2;

三、執行時棧

1.非遞迴函式

非遞迴函式被呼叫時,系統需要儲存:

a.呼叫函式的返回位址

b.呼叫函式的區域性變數值

2.遞迴函式

遞迴函式被呼叫時,系統也需要儲存以上資訊。但遞迴函式的執行特點,是最後呼叫的函式最先返回,若按照以上方法儲存資訊會出錯。由於棧的後進先出的特性與遞迴函式呼叫返回的過程吻合,一般可以使用棧來儲存遞迴函式呼叫時的資訊。

系統用於儲存遞迴函式呼叫資訊的棧就稱為執行時棧。

每一層遞迴呼叫所儲存的資訊構成執行時棧的一條工作記錄。每進入下一層遞迴呼叫時,系統就新建一條工作記錄,並將此條工作記錄進棧成為執行時棧的新的棧頂;每返回一層遞迴呼叫,就退棧一條工作記錄。

因此,棧頂的工作記錄必定是當前執行遞迴函式的工作記錄,所以棧頂的工作記錄也稱活動記錄

當呼叫遞迴函式時,除了要儲存呼叫函式的返回位址,還需要儲存本次呼叫函式的實參值、區域性變數值和函式返回值(函式名變數的值)。

四、遞迴演算法的設計方法

遞迴演算法的基本思想:是把乙個相對複雜的問題,分解成若干個相對簡單且類同的子問題,對簡單到一定程度的子問題直接求解,從而也得到原問題的解。

適用於遞迴演算法求解的問題的充分必要條件:

a.問題具有某種可借用類同子問題描述的性質;

b.某一有限步子問題(本原問題)有直接的解存在。

設計遞迴演算法的方法:

a.把對原問題的求解設計成包含對子問題求解的形式;

b.設計遞迴出口。

例:漢諾塔問題

public void move(int n,char from,string buffer,string to) else 

}

五、遞迴演算法到非遞迴演算法的轉換一般來說存在以下兩種情況的遞迴演算法:

1.存在不借助棧的迴圈結構的非遞迴演算法,如階乘問題、fibonacci數列、折半查詢。

2.存在借助棧的迴圈結構的非遞迴演算法,如漢諾塔問題。

所有遞迴演算法都可以借助棧轉換為迴圈結構的非遞迴演算法。所有遞迴演算法都可以用樹結構表示。

例:用棧模擬漢諾塔問題

class problem	

}

每次將棧頂元素出棧,然後解決棧頂元素,拆分為子問題或結果。知道棧內沒有元素。如圖: 

//用棧模擬遞迴實現漢諾塔

public void movebystack(int n,char from,char buffer,char to)

"s1 pop:"+s1.pop());

list> list=new arraylist<>();    //把 from,buffer,to都先初始化起來,加到list中

list.add(s1);

list.add(new stack());

list.add(new stack());

while(!stack.isempty()&&((p=stack.pop())!=null)) else

} }//對應的下標與位置

public int indexdecode(char n)

}

測試一下兩者的速度差異:(這裡把以上方法中的輸出語句全部注釋掉,只計算移動次數)

static long count1=0l;

static long count2=0l;

public static void main(string args)

結果:遞迴比迴圈快,而且快很多,原因是執行緒棧要比手動建立的stack效能好太多了。

8388607次

*************************=

8388607次

遞迴:16ms

迴圈:773ms

所以在遞迴深度不太大的時候,當沒有更簡潔的迴圈演算法時,使用遞迴要比使用棧模擬遞迴來的好。如果遞迴深度太大,又沒有不使用棧結構的迴圈演算法時,才考慮使用棧模擬遞迴。

下面測試下遞迴深度:(win10-64bit jdk 9.0.1 預設設定[1m])

class stacklevel

}

public static void main(string args)  catch (stackoverflowerror e) 

}

結果:24466

如果把stacklevel中注掉的三條變數恢復,則結果是6697。原因是每次遞迴要儲存的資訊變多了。

參考:資料結構-第6章.遞迴演算法

演算法分析設計 遞迴演算法

what s the 遞迴演算法 定義 程式直接或間接呼叫自身的程式設計技巧稱為遞迴演算法 recursion 乙個過程或函式在其定義或說明中又直接或間接呼叫自身的一種方法,它通常把乙個大型複雜的問題層層轉化為乙個與原問題相似的規模較小的問題來求解,遞迴策略只需少量的程式就可描述出解題過程所需要的多...

遞迴下降分析程式設計 演算法講解之遞迴演算法

前面已經介紹了關於遞迴呼叫這樣一種操作,而遞迴程式設計是c 語言程式設計中的一種重要的方法,它使許多複雜的問題變得簡單,容易解決了。遞迴特點是 函式或過程呼叫它自己本身。其中直接呼叫自己稱為直接遞迴,而將a呼叫b,b以呼叫a的遞迴叫做間接遞迴。例1 給定n n 1 用遞迴的方法計算1 2 3 4 n...

演算法分析之遞迴策略

遞迴演算法 直接或間接地呼叫自身的演算法稱為遞迴演算法。用函式自身給出定義的函式稱為遞迴函式。使用遞迴技術往往使函式的定義和演算法的描述簡捷且易於理解。特點 1 遞迴就是在過程或函式裡呼叫自身。2 在使用遞迴策略時,必須有乙個明確的遞迴結束條件,稱為遞迴出口。3 遞迴演算法解題通常顯得很簡潔,但遞迴...