1. 程式人生 > 其它 >遞推法與遞迴法

遞推法與遞迴法

遞迴演算法

  1. 遞迴演算法是一種從自頂向下的演算法 ,實際上是通過不停的直接呼叫或者間接的呼叫自身的函式,通過每次改變變數完成多個過程的重複計算,直到到達邊界之後,結束呼叫。

  2. 與遞推法相似的是,遞迴與遞推都是將一個複雜過程分解為幾個簡單重複步驟進行計算。

  3. 實現的核心是分治策略,即分而治之,將複雜過程分解為規模較小的同類問題,通過解決若干個小問題,進而解決整個複雜問題。

  4. 遞迴演算法設計的一般步驟:

    1. 根據題目設計遞迴函式中的運算部分;
    2. 根據題目找到遞迴公式,題目可能會隱含給出,也可能需要自己進行推導;
    3. 找到遞迴出口,即遞迴的終止條件。

    遞推演算法(迭代)

    1. 一個問題的求解需要大量重複計算,在已知的條件和所求問題之間總存在著某種相互聯絡的關係,在計算時,我們需要找到這種關係,進行計算(遞推關係式)。
    2. 即遞推法的關鍵,就是找到遞推關係式,這種處理方式能夠將複雜的計算過程,轉化為若干步驟的簡單重複運算。

例題1:

題目描述:

斐波那契數列(Fibonacci sequence),又稱黃金分割數列,因數學家萊昂納多·斐波那契(Leonardoda Fibonacci)以兔子繁殖為例子而引入,故又稱為“兔子數列”。

指的是這樣一個數列:0、1、1、2、3、5、8、13、21、34、……

在數學上,斐波那契數列以如下被以遞推的方法定義:F(0)=0,F(1)=1, F(n)=F(n - 1)+F(n - 2)(n ≥ 2,n ∈ N*)

請求出該數列中第n個數字(n從1開始計數)是多少。

樣例:

輸入樣例

樣例輸入
6
輸出
8

對應的計算過程:

[0]=0
[1]=1
[2]=0+1
[3]=1+1=2
[4]=1+2=3
[5]=2+3=5
[6]=5+3=8

題目解析:

  1. 遞迴式,F(n)= F(n-1) + F(n-2)

  2. F(n)=0 n=0 ,F(n)=1 n=1 這就是遞迴出口,能讓遞迴停止的條件。

遞推法實現:

import java.util.Scanner;
public class Main {

    public static void main(String[] args) {
        int n; //第幾個數
        int x=0; //F(n)
        int y=1; //F(n+1)
        int ans = 0; //F(n+2)
        Scanner in = new Scanner(System.in);
        n = in.nextInt();
        if(n==0) ans=0;
        else if(n==1) ans=1;
        else {
            for(int i=2;i<=n;i++)
            {
                ans=x+y;
                x=y;
                y=ans;
            }
        }

        System.out.println(ans);
    }
} 

遞迴法實現:

import java.util.Scanner;
public class Main {

    static  int fn(int n)
    {
        if(n==0)
            return 0;
            //遞迴出口2
        else if(n==1 )
            return 1;

        else
            return fn(n-1)+fn(n-2); //遞迴關係式
    }

    public static void main(String[] args) {
        int n; //第幾個數
        int ans = 0;
        Scanner in = new Scanner(System.in);
        n = in.nextInt();
        ans=fn(n);       
        System.out.println(ans);
    }
}

例題2: (題目分儲存和非儲存的,若是需要多次詢問資料,就採取儲存的方式)

題目描述:

這樣一個數列:0、1、1、2、3、5、8、13、21、34、……

在數學上,斐波那契數列以如下被以遞推的方法定義:F(0)=0,F(1)=1, F(n)=F(n - 1)+F(n - 2)(n ≥ 2,n ∈ N*)。

我們將進行M次查詢,每次輸入一個N,其中n小於30。

請求出該數列中第n個數字(n從1開始計數)是多少?

樣例:

輸入樣例

樣例1輸入:

6
4
2
7
8
8
10
輸出樣例

樣例1輸出:

3
1
13
21
21
55

題目解析:

這道題跟上面一道題的演算法原理相同,只是增加了多次查詢的複雜度;

將每次訪問的結果都儲存在陣列中,陣列的下標正好與n對應起來

陣列的長度就是n的取值範圍;

遞推法實現:

import java.util.Scanner;

public class DiGui1 {
	
	//將每次訪問的結果都儲存在陣列中,陣列的下標正好與n對應起來
	static int[] result = new int[35];
	
	//實現每次計算
	static void danci() {
		result[0] = 0;
		result[1] = 1;
		for(int i=2;i<=30;i++) {
			result[i] = result[i-1] + result[i-2];
		}
	}
	public static void main(String[] args) {
		 
		Scanner scanner  = new Scanner(System.in);		
		int m = scanner.nextInt();//m次的查詢
		
		danci(); //因為此函式不需要傳引數,執行一次,就將n從0到30的結果都儲存到結果陣列中,所以寫到每次迴圈的外面
		
		//查詢m次
		while(m>0) {
			m--;
			//要查詢的值對應的n,在迴圈體內輸入
			int n = scanner.nextInt();
			System.out.println(result[n]);
			 
		}
	}
}

遞迴法實現:

import java.util.Scanner;

public class DiGui2 {

	// 將每次訪問的結果都儲存在陣列中,陣列的下標正好與n對應起來
	static int[] result = new int[35];

	// 實現每次計算
	static int danci(int n) {
		// 遞迴出口1
		if (n == 0) {
			result[0] = 0;
			return 0;
		} else if (n == 1) {
			result[1] = 1;
			return 1;
		} else {
			result[n] = danci(n - 1) + danci(n - 2);
			return result[n];
		}
	}

	public static void main(String[] args) {

		Scanner scanner = new Scanner(System.in);
		int m = scanner.nextInt();// m次的查詢
		// 因為遞迴底層運算是從n=0 一直到n=30,執行一次,就將n從0到30的結果都儲存到結果陣列中,所以寫到每次迴圈的外面
		danci(30);
		// 查詢m次
		while (m > 0) {
			m--;
			// 要查詢的值對應的n,在迴圈體內輸入
			int n = scanner.nextInt();
			System.out.println(result[n]);
		}
	}
}

總結:

對於以上兩種方式實現儲存型的遞推與遞迴,都是先把各個結果得出,儲存到陣列中儲存起來,那多次訪問,就不用每次都計算一下。