简介
这是之前发的一道简单的PAT题目–数素数(PAT1013),由于这道题官方要求的素数范围极小,所以暴力遍历即可解决。
素数暴力求法(未优化)
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <cmath>
using namespace std;
int prime[10005];
bool isPrime(int i)
{
for(int j = 2; j <= (int)sqrt(i); j++)
{
if(i % j == 0)
{
return false;
}
}
return true;
}
int main(void)
{
int num = 0;
int i = 0;
int begin = 0, end = 0;
int count = 1;
memset(prime, 0, sizeof(prime));
scanf("%d %d", &begin, &end);
for(i = 2;; i++)
{
if(num == end)
{
break;
}
if(isPrime(i))
{
prime[num++] = i;
}
}
for(i = begin - 1; i <= end - 1; i++)
{
if(count % 10 != 0)
{
if(i == end - 1)
{
printf("%d", prime[i]);
break;
}
printf("%d ", prime[i]);
count++;
}
else
{
printf("%d\n", prime[i]);
count++;
}
}
return 0;
}
经过优化后,我们在3之后只求奇数,让目标奇数只与之前求过的素数取余,且把遍历素数范围控制在sqrt(已求素数总数)范围内。
优化后的暴力代码
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <cmath>
using namespace std;
int prime[10005];
int main(void)
{
int num = 2;
int i = 0, j = 0;
int begin = 0, end = 0;
int count = 1;
memset(prime, 0, sizeof(prime));
scanf("%d %d", &begin, &end);
prime[0] = 2;
prime[1] = 3;
for(i = 5; ; i += 2) //只求奇数
{
if(num >= end)
{
break;
}
for(j = 0; j <= (int)sqrt(num); j++) //缩减循环次数
{
if(i % prime[j] == 0) //与之前已经求过的prime数组中的数取余
{
break;
}
else
{
if (j + 1 > (int)sqrt(num))
{
prime[num++] = i;
break;
}
}
}
}
for(i = begin - 1; i <= end - 1; i++)
{
if(count % 10 != 0)
{
if(i == end - 1)
{
printf("%d", prime[i]);
break;
}
printf("%d ", prime[i]);
count++;
}
else
{
printf("%d\n", prime[i]);
count++;
}
}
return 0;
}
优化后的算法遍历大规模素数的时间是原算法的一半。
测试
优化前
优化后