在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
参考来源:https://blog.csdn.net/fall221/article/details/9158703 用 C++ 重现了一遍。
例子:裴波拉契数列: 1,1,2,3,5,8,。。。 用递归求第 n 项: 上面这个算法的时间复杂度是 O(2^n),比如 fab(6) = fab(5) + fab(4) = fab(4) + fab(3) + fab(3) + fab(2) = fab(3) + fab(2) + fab(2) + fab(1) + fab(2) + fab(1) + fab(2) = fab(2) + fab(1) + fab(2) + fab(2) + fab(1) + fab(2) + fab(1) + fab(2) 如果不是从 fab(6) 开始,是从 fab(n) 开始,n 又足够大,上式中每行 fab() 个数为 1,2,4,8,16,。。。 所以 fab() 被调用的次数为 O(2^n) 数量级,时间复杂度为 O(2^n)
这个算法已经包括了动态规划的意思,从 fab(0), fab(1) 出发,迭代大约 n 次,即可得到结果,时间复杂度为 O(n),所以算法本身就更优越。
cout<<"fabonacci(n)="<<fabonacci(n)<<endl;
编译: g++ main.cpp -o main.o
n=50 ... time to calculate normal recursion:186s time to calculate tail recursion:0s 这很正常。下面是重点——关于尾递归优化。 如果不加 -O2,编译时不会自动做尾递归优化,(我估计)每次递归没有擦去上次的栈帧,所以空间复杂度还是 O(n)。可做实验:注掉调用 fabonacci(n) 那一行,即只测试尾递归,进行编译 g++ main.cpp -o main.o ./main.o n=1000000 segmentation fault (core dumped) 据我目测,估计是栈内存溢出了。 但如果加上 -O2 进行编译,就可实现尾递归优化 g++ main.cpp -o main.o -O2 ./main.o n=10000000000 tail recursion: fabonacci(n)= -1.07027e+09 time to calculate tail recursion: 3s 上面的结果中,fabonacci(n)= -1.07027e+09 为负值是因为超出了整型范围。但 n=10^{10} 也可以算出来,说明栈内存没有爆。据我目测,耗时 3s 是正常的,因为 10^10 次加法,cpu 3点几的GHz,差不多。
另写了个循环函数 double iter_fabonacci(int a, int b, int n){ 然后测试了这个循环函数与尾递归函数(开启尾递归优化,即开启 -O2)的耗时对比,如下图
用的是 c++ time.h 里的 clock_t 类型,以及 clock() 函数,比如: clock_t t_start=clock(); cout<<CLOCKS_PER_SECOND<<endl; 会输出 1000000,即单位是 1/1000000 s = 1 微秒。 ----------------------------------------------------------------------------------------------------------- 我发现了一个问题,如果在尾递归函数中加入一行: double tail_fabonacci(int a, int b, int n){ cout<<&a<<"\t"<<&b<<endl;
新加入的这一行 cout<<&a<<"\t"<<&b<<endl; 本意是想看看内存地址的变化,看看是不是真的没有栈开销,但加入这一行以后,再用 “-O2” 编译,运行可执行文件,发现 n=1000000 时就报错 “segmentation error”,似乎尾递归优化失效,和没有加 “-O2” 没有区别了。 |
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论