1. 程式人生 > >遞迴法的應用:求解斐波那契數列和數字的組合問題

遞迴法的應用:求解斐波那契數列和數字的組合問題

  • 遞迴:是指函式、過程、子程式在執行過程中直接或間接呼叫自身而產生的重入現象。採用遞迴編寫程式能是程式變的見解和清晰。
  • 遞迴的用法一般為:
    • 定義是遞迴的:有許多數學公式、樹、數列等的定義是遞迴的。
    • 資料結構是遞迴的:單鏈表就是一種遞迴的資料結構。
    • 問題的求解方法是遞迴的:有些問題的求解方法是遞迴的,典型的有Hanoi塔問題求解。
  • 但遞迴也有缺點,該演算法解題的運算效率低,在遞迴呼叫過程中系統為每一層的返回值、區域性變數等開闢了棧空間來儲存,遞迴次數過多容易造成棧溢位。
  • 能採用遞迴描述的演算法通常有這樣的特徵:為求解規模為N的問題,設法將其分解為規模較小的問題,然後從這些小問題的解方便的結構造出大問題的解,並且這些規模較小的問題也採用同樣的分解和綜和方法分解成規模更小的問題,並且這些更小問題的解構造出規模較大問題的解。它包括遞迴出口和遞迴體兩部分,前者確定何時結束遞迴,後者確定遞迴求解的遞推關係。

題目1:編寫計算fibonacci數列的第n項函式fib(n)。

  • 首先來看一下迴圈的版本:
int fib(int n)
{
	int result[3] = {0, 1, 1};
	if(n <= 2)
	{
		return result[n];
	}
	int fibfirst = 0;
	int fibsecond = 1;
	int fibn = 0;
	while(n > 1)
	{
		fibn = fibfirst + finsecond;
		fibnfirst = fibsecond;
		finsecond = fibn;
		n--;
	}
	return fibn;
}
  • 遞迴版本
int fibn(int n)
{
	if(n == 0)
		return 0;
	if(n == 1)
		return 1;
	if(n > 1)
		return fibn(n - 1) + fibn(n - 2);
}
  • 從這兩個例子我們看見了遞迴的魅力,他把複雜問題的求解分解為簡單的小問題來分別求解,在根據簡單小問題的解來構造複雜問題的解。這使得程式碼看起來清晰,簡單。

題目2:數字組合問題。找出自然數1,2,3,. . . . . .,n。中任取 r 個數的所有組合(r <= n)。

  • 解法描述:當組合的第一個數選定時其後的數字是從餘下的n-1個數字中選取r-1個數的組合,這樣將求n個數中r個數的組合轉化為求n-1個數中r-1個數的組合問題。在函式中使用一個工作陣列來存放求出組合的數字,約定函式將確定的r個數字組合的第一個數字存放在arr[r]中,當第一個組合求出後,才將arr[]中的一個組合輸出,第一個數可以是n,n-1,…,r,函式將確定組合的第一個數字放入陣列後,有兩種可能的選擇,因還未去掉組合的其餘元素,繼續遞迴確定;或者已經確定了組合的全部元素,輸出這個組合。
#include<iostream>
using namespace std;
int arr[100];
void com(int n, int r)
{
	int i = 0, j = 0;
	for(i = n; i >= r; i--)
	{
		arr[r] = i;
		if(r == 1)
		{
			for(j = 1; arr[j] > 0; j++)
			{
				cout << arr[j] << " ";
			}
			cout << endl;
			continue;
		}
		com(i - 1, r - 1);
	}
}
int main()
{
	int i = 0;
	for(i; i < 100; i++)
	{
		arr[i] = 0;
	}
	int n, r;
	cin >> n >> r;
	com(n, r);
	return 0;
}

測試結果如下圖: 在這裡插入圖片描述