1. 程式人生 > >部分函式的遞迴與迭代(非遞迴)實現

部分函式的遞迴與迭代(非遞迴)實現

部分函式的遞迴和迭代(非遞迴)實現

首先,說到遞迴函式,大家一般都會想到斐波那契數列計算階乘這兩種,書本上大多也是以這兩個為例,下面就簡單介紹一下這兩個吧。

斐波那契數列:

1 1 2 3 5 8......這樣的數列叫做斐波那契數列,規律很簡單,前兩個數字的和就是第三個數字的值。
我們可以簡單表示為:

            n>2    fib(n)=fib(n-1)+fib(n-2)

fib(n)

            n<=2   fib(n)=1

遞迴的實現程式碼也是比較簡單的;只需要函式不斷呼叫自身就可以了:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>

int fib_1(int n)//採用遞迴的方式做的
{
	if (n <= 2)
		return 1;
	else
		return fib(n - 1) + fib(n - 2);
}
int main()
{
	int n = 0;
	scanf("%d", &n);
	printf("%d", fib_1(n));
	system("pause");
	return 0;
}

當然,這看上去很容易理解,但是,這卻不是最好的方法。主要就是因為每一個遞迴呼叫都會觸發另外兩個遞迴呼叫,這樣,冗餘計算的數量增長的非常快。例如,在計算fib(10)的時候,fib(3)被呼叫了21次,而計算fib(30)的時候,fib(3)被計算了30多萬次,這很浪費,而且效率很低。

所以,我們可以用一個簡單迴圈來代替遞迴,雖然理解起來不如遞迴那麼簡單,但是效率提高了太多。

迭代的程式碼實現也是比較簡單的,只要用一個迴圈,就以a,b,c三個數字舉例吧,讓c=a+b;得到的結果給b,再把之前b的值賦給a,這樣同樣實現了斐波那契數列的規律:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>

int fib_2(int n)//採用函式的方式做
{
	int i = 0;
	int a = 0;
	int b = 1;
	int c = 0;
	if (n <= 2)
		return 1;
	else
	{
		for (i = 0; i < n - 1; i++)
		{
			c = a + b;
			a = b;
			b = c;
		}
		return c;
	}
}

int main()
{
	int n = 0;
	scanf("%d", &n);
	printf("%d", fib_2(n));
	system("pause");
	return 0;
}

計算階乘:

階乘大家也都知道,就是一個數不斷乘上自身的-1;也就是n*(n-1)*...*1。

這可以簡單表示為:

             n=0    fac(n)=1

fac(n)

             n>0    fac(n)=n*fac(n-1)

遞迴的程式碼實現也是比較容易的:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>

int fac_1(int n)
{
	if (n <= 0)
	{
		return 1;
	}
	else
	{
		return n*fac_1(n - 1);
	}
}


int main()
{
	int n = 0;
	scanf("%d", &n);
	printf("%d\n", fac_1(n));
	system("pause");
	return 0;
}

當然,這和上面的斐波那契數列一樣,效率很低,主要就是因為,在呼叫函式的時候,引數會被壓到堆疊中,為區域性變數分配記憶體空間(基本上所有的遞迴函式都是如此),每一的呼叫返回時,這些都必須還原,所以,這裡產生了很大的開銷。

同樣的,用一個簡單迴圈就可以完成相同的任務:

只要不斷乘上自身減1就可以了,知道自身不能再減為止。

程式碼實現如下:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>

int fac_2(int n)
{
	int ret = 1;
	while (n > 1)
	{
		ret *= n;
		n--;
	}
	return ret;
}

int main()
{
	int n = 0;
	scanf("%d", &n);
	printf("%d\n", fac_2(n));
	system("pause");
	return 0;
}

這裡程式碼的簡潔性可以彌補遞迴帶來的執行時開銷,就上面所得呼叫函式時的開銷。

另外,我在這裡提一下用遞迴的方式輸出數字:

以1234這個數字為例,要求螢幕上輸出1 2 3 4;

程式碼如下:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>

void print(int num)
{
	if (num > 10)
	{
		print(num/10);//這裡採用遞迴的方式
	}
	printf("%d ", num % 10);
}

int main()
{
	int num = 0;
	scanf("%d", &num);
	print(num);
	system("pause");
	return 0;
}

這裡需要對遞迴有很好的理解;還是以1234為例,第一次進入函式,1234>10,那麼會再次進入函式,不過是以123的大小進入,同樣,123還是大於10,再次以12進入,12還是大於10,那麼就再次以1進入函式,這次1<10了,那麼函式就會列印1%10的結果,就是1;

接著函式呼叫返回,列印12%10的結果,就是2;以此類推,最後輸出的結果就是4了,這樣螢幕上就會顯示出1 2 3 4 這樣的數字了;這裡就很好的演示了遞迴。

還有什麼不足敬請提出,讓我加以修改。