fibonacci递归算法的“备忘录/Memo”优化法

        我们先看一个简单的fibonacci递归程序:

#include <iostream>
#include <windows.h>
using namespace std;

int fun(int n)
{
	if(1 == n || 2 == n)
	{
		return n;
	}

	return fun(n - 1) + fun(n - 2);
}

int main()
{
	int i = 0;
	int n = 1000; // 计算1000次

	int t1 = GetTickCount();
	for(i = 0; i < n; i++)
	{
		fun(30);
	}

	int t2 = GetTickCount();
	cout << t2 - t1 << endl;

	return 0;
}

        耗费时间(单位毫秒):47890

        仔细画图分析就可知, 上述递归存在重复计算问题, 下面, 我们用备忘录法来试试:

#include <iostream>
#include <windows.h>
using namespace std;

int a[50] = {0};

int funWithMemo(int n)
{
	if(1 == n || 2 == n)
	{
		a[n] = n;
		return a[n];
	}

	if(0 != a[n])
	{
		return a[n];
	}

	int x = funWithMemo(n - 1);
	int y = funWithMemo(n - 2);
	a[n] = x + y;

	return a[n];
}


int main()
{
	int i = 0;
	int n = 1000; // 计算1000次

	int t1 = GetTickCount();
	for(i = 0; i < n; i++)
	{
		funWithMemo(30);
	}

	int t2 = GetTickCount();
	cout << t2 - t1 << endl;

	return 0;
}

        结果为:0  . 程序快得离谱啊, 我们看看, 哪里不公平了, 原来, a中已经存放值了, 所以后面每次都是return a[30];了, 所以, 循环测试的时候, 失去了一点公平性, 好吧, 我们来改改:

#include <iostream>
#include <windows.h>
using namespace std;

int a[50] = {0};

int funWithMemo(int n)
{
	if(1 == n || 2 == n)
	{
		a[n] = n;
		return a[n];
	}

	if(0 != a[n])
	{
		return a[n];
	}

	int x = funWithMemo(n - 1);
	int y = funWithMemo(n - 2);
	a[n] = x + y;

	return a[n];
}


int main()
{
	int i = 0;
	int n = 1000; // 计算1000次

	int t1 = GetTickCount();
	for(i = 0; i < n; i++)
	{
		memset(a, 0, 50 * sizeof(int)); // 为了公平起见, 在循环测试中, 数组每次清零
		funWithMemo(30);
	}

	int t2 = GetTickCount();
	cout << t2 - t1 << endl;

	return 0;
}

       结果, 程序还是0, 可见, 确实快。

       我们加大测试次数, 程序如下:

#include <iostream>
#include <windows.h>
using namespace std;

int a[50] = {0};

int funWithMemo(int n)
{
	if(1 == n || 2 == n)
	{
		a[n] = n;
		return a[n];
	}

	if(0 != a[n])
	{
		return a[n];
	}

	int x = funWithMemo(n - 1);
	int y = funWithMemo(n - 2);
	a[n] = x + y;

	return a[n];
}


int main()
{
	int i = 0;
	int n = 10000; // 加大到1万次

	int t1 = GetTickCount();
	for(i = 0; i < n; i++)
	{
		memset(a, 0, 50 * sizeof(int)); // 为了公平起见, 在循环测试中, 数组每次清零
		funWithMemo(30);
	}

	int t2 = GetTickCount();
	cout << t2 - t1 << endl;

	return 0;
}

       结果为:16.  可见, 程序确实快。 funWithMemo之所以这么快, 是因为它采用了备忘录, 避免了重复的不必要的计算。(实际上, 16毫秒还包括了数组清零的时间)

 

       采用递归, 对于编程人员来说, 非常方便, 但效率低下, 此时, 再引入备忘录, 有时效率会有所提升。 其实, 无论是递归带不带备忘录, 速度都不如自底向上的动态规划算法。

       OK, 本文先闲聊到这里。

       

    原文作者:递归算法
    原文地址: https://blog.csdn.net/stpeace/article/details/46673831
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞