尝试优化和理解打印数字除数的递归函数的运行时
Trying to optimize and understand runtime on a recursive function that prints divisors of a number
下面是一个递归函数,它打印一个数字的除数(它必须是递归的(。
如果没有注释掉的部分,程序最坏的情况是素数,while 循环必须一直运行到 n,因此运行时将是:O(n(。
对于注释部分,素数现在在 O(sqrt(n(( 上运行,但在不是素数的数字上它会变慢,但 for 循环在任何情况下都应该使计数到除数的速度更快。谁能解释为什么运行时更慢?
如果有人想自己检查,我已经包括了时钟部分,这里有一些大的素数:1073676287。
#include<iostream>
#include <math.h>
#include <ctime>
using namespace std;
void f(long long number);
void main()
{
clock_t begin = clock();
f(1844674407370955161);
clock_t end = clock();
cout << endl << double(end - begin) / CLOCKS_PER_SEC << endl;
}
void f(long long n)
{
long long divisor = 2;
long long sn = sqrt(n), i;
int trigger = 0;
if (n == 1) return;
//else if (n != 1)
//{
// for (i = 2; i <= sn; i++)
// {
// if (n%i == 0)
// trigger++;
// }
// if (trigger == 0)divisor = n;
//}
while ((n % divisor) && (n > divisor))
divisor++;
cout << divisor << " ";
f(n / divisor);
}
问题分析:
问题很明显:您注释的for
循环将在递归调用中执行 1.641.428.459 次,每次在long long
上执行模块操作。 这需要一些时间! 这解释了它几乎是 3 倍长(在我的 PC 上大约 40 秒(
首先,这个 for 循环根本没有优化! 以下:
for (i = 1; i <= sn; i++)
...
if (trigger == 0) divisor = n;
可以简化,因为trigger
仅用于知道它是否为 0:
for (i = 1; !trigger && i <= sn; i++) { // if trigger is set, no use to continue !!
if (n%i == 0)
trigger++;
}
if (trigger == 0) divisor = n;
通过此更改,您的其他代码将获得可接受的性能。 但是,此代码仍然不会加速任何内容。 总体而言,它仍然比没有慢 100 毫秒,大约需要 15.5 秒才能获得结果。
B.Kernighan曾经说过">不要嘻嘻代码,找到更好的算法":看看你的回避代码和for
循环,我们可以看到,每次递归都盯着1进行同样的i
计算。 但是,如果 2 或 3 或 5 不是第一次除数,那也不会是 secont 时间! 因此,我们可以优化递归:
优化递归
使用以下代码,您可以获得 1.3 秒的结果,而 15.5 秒的速度快 10 倍以上:
void f(long long number, long long last_divisor=2); // 2 parameters, 1 being by default
void f(long long n, long long last_divisor)
{
long long divisor = last_divisor; // we don't start at 2 anymore
long long sn = sqrt(n), i;
int trigger = 0;
if (n == 1) return;
else if (n != 1)//optimisation in case given number is a prime
{
for (i = last_divisor; !trigger && i <= sn; i++) { // we don't start at 1 anymore
if (n%i == 0)
trigger++;
}
if (trigger == 0)divisor = n;
}
while ((n % divisor) && (n > divisor))
divisor++;
cout << divisor << " ";
f(n / divisor, divisor); // tell recursion where we've stopped !
}
相关文章:
- 递归函数计算序列中的平方和(并输出过程)
- 无穷大而循环时具有递归函数
- 这个递归函数有什么作用?运行时的复杂性是多少?
- 跟踪递归函数时出现问题
- 使用递归函数 (c++) 将长字符串转换为整数时输出错误
- 当有 2 个或更多递归函数写入 togeather 时,程序如何执行?
- 执行递归函数时 C++ 应用程序崩溃
- 为什么当从递归函数返回字符串到C 中的Main时,我会得到分割错误
- 满足动态条件时退出递归函数
- 在递归函数中释放内存时堆损坏
- 如何使这个递归函数运行得更快
- 当我在递归函数中调用 return 时,我的程序意外完成
- 为什么当递归函数结果相乘时,g++ 仍然优化尾递归
- 实现用于查找路径的递归函数时出现问题
- 尝试优化和理解打印数字除数的递归函数的运行时
- 将数组传递给递归函数 c++ 时遇到问题
- 在运行递归函数时将新元素插入向量时出现问题
- 递归函数的Big Theta(Θ)运行时
- C++ 使用递归函数时的堆栈溢出
- 通过引用递归函数传递字符串或流对象时出现的段错误