赞
踩
1.了解影响程序运行时间的主要因素;
2.掌握渐近时间复杂度的表示方法;
3.掌握递归关系的时间复杂度计算。
原理:
程序:
#include <iostream> using namespace std; void hanoi(int n,int p1,int p2,int p3) //p1,p2,p3表示利用2号将1号的n个珠子移动到3号 { if(1==n) cout<<"盘子从"<<p1<<"移到"<<p3<<endl; //递归函数退出点,当珠子数量为1时,直接移动,结束 else { hanoi(n-1,p1,p3,p2); //第一步p1,p3,p2表示利用3号将1号的n-1个珠子移动到2号 cout<<"盘子从"<<p1<<"移到"<<p3<<endl; //第二步将剩余的一个珠子从1移到3 hanoi(n-1,p2,p1,p3); //第三步p2,p1,p3表示利用1号将2号的n-1个珠子移动到3号 } } int main() { cout<<"姓名:张俊 学号:201802524 :\n"; int a,p1=1,p2=2,p3=3; //定义移动的珠子数a,以及三个杆子 cout<<"请输入在一号杆上的珠子数:"; cin>>a; //用a接受输入的珠子数 hanoi(a,p1,p2,p3); //调用递归函数,实现a个珠子通过p2从p1移动到p3 return 0; }
测试:
时间复杂度:
设盘子个数为n时,需要T(n)步,把A柱子n-1个盘子移到B柱子,需要T(n-1)步,A柱子最后一个盘子移到C柱子一步,B柱子上n-1个盘子移到C柱子上T(n-1)步。
得递推公式T(n)=2T(n-1)+1
所以汉诺塔问题的时间复杂度为O(2^n);
#include <iostream> using namespace std; long Fib(int n) { if (n == 0) return 0; //递归调用出口 if (n == 1) return 1; //递归调用出口 if (n > 1) return Fib(n-1) + Fib(n-2); //数为前两个数总和 return 0; } int main() { cout<<"姓名:张俊 学号:201802524:\n"; int month; //定义总数month cout<<"请输入总数:"; cin>>month; //输入值赋给参数month cout<<"经过"<<month<<"次生成后,总总数为:"<<Fib(month)+Fib(month-1); //调用两次递归函数,参数分别是month和month-1 //计算总数 return 0; }
测试:
以12为测试:
复杂度:
这样的递归算法虽然只有简单的几行,但是效率却很低。
时间复杂度 ----- O(2^N)
由于使用递归时,其执行步骤是:要得到后一个数之前必须先计算出之前的两个数,即在每个递归调用时都会触发另外两个递归调用,例如:要得到F(10)之前得先得到F(9)、F(8),那么得到F(9)之前得先得到F(8)、F(7)…如此递归下去
使用非递归实现:
原理:
要想非递归实现斐波拉契函数,只要保存f(n-2)、f(n-1)就可以,将其存入list中。当n=2时,只需要把list中的两个数相加一次即可,同时将相加的数存入list[1],将原来的list[1]存入list[0]中。
程序:
#include <iostream> using namespace std; int fibFor(int n); //声名生成斐波拉契数列的函数 int main() { cout << "姓名:张俊 学号:201802524\n"; int n; cout << "n="; cin >> n; //输入总数 cout << "结果:" << fibFor(n) << endl; //打印函数调用运行结果 return 0; } int fibFor(int n) { //定义函数主体 int a = 1; int b = 1; //初始两个值1,1 int result; //最终结果 if (n <= 1) return 1; //如果n小于1,直接退出 else { for (int i = 1; i < n; i++) { result = a + b; a = b; b = result; } return result; } //否则将前两个数相加赋值给第三个数 并输出 }
测试:
复杂度:
时间复杂度为O(N),空间复杂度为O(1)
借助两个变量a 和 b ,每次将 a 和 b 相加后赋给 result ,再将 b 赋给 a ,result 赋给 b,如此循环。
比较递归和非递归:
由于使用递归时,其执行步骤是:要得到后一个数之前必须先计算出之前的两个数,即在每个递归调用时都会触发另外两个递归调用,例如:要得到F(10)之前得先得到F(9)、F(8),那么得到F(9)之前得先得到F(8)、F(7)…如此递归下去
从上图我们可以看出,这样的计算是以 2 的次方在增长的。除此之外,我们也可以看到,F(8)和F(7)的值都被多次计算,如果递归的深度越深,那么F(8)和F(7)的值会被计算更多次,但是这样计算的结果都是一样的,除了其中之一外,其余的都是浪费,可想而知,这样的开销是非常恐怖的!
说明:
代码中一定位置或注释中一定要加入能标记自己身份的信息,如学号、姓名等。
粘贴在Word中的代码最好保留原始着色,一定要清楚,有缩进,有注释。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。