原始版素数表
最初刚接触算法的时候,使用了原始的方法来输出素数表:
void originalPrime()
{
long p, d, input;
int isPrime;
printf("input a number:");
scanf("%li", &input);
for (p = 2; p <= input; p++) {
isPrime = 1;
for (d = 2; d < p; d++) {
if (0 == p % d) {
isPrime = 0;
}
}
if (isPrime) {
printf("%li\n", p);
}
}
}
这个就是简单的for循环嵌套,来寻找素数。
不过这个算法效率比较低,时间复杂是O(n * n!)。
改进版素数表
后来知道了如果一个数是合数,那么它的最大质因子不会大于它的平方根——sqrt(x)。
(质因子的概念
质因子(或质因子)在数论里是指能整除给定正整数的质数。两个没有共同质因子的正整数称为互质。因为1没有质因子,1与任何正整数(包括1本身)都是互质。正整数的因数分解可将正整数表示为一连串的质因子相乘,质因子如重复可以指数表示。根据算术基本定理,任何正整数皆有独一无二的质因子分解式。只有一个质因子的正整数为质数。)
于是,算法改进了下:
void increPrime()
{
long p, d, input;
int isPrime;
printf("input a number:");
scanf("%li", &input);
for (p = 2; p <= input; p++) {
isPrime = 1;
for (d = 2; d <= sqrt(p) ; d++) {
if (0 == p % d) {
isPrime = 0;
}
}
if (1 == isPrime) {
printf ("%li\n", p);
}
}
}
这里不再判断d到p的所有值了 ,只到p的平方根即可,速度提升了一些。
筛选法素数判定
还有效率超高的,就是筛选法。
筛选法先初始化一个数组prime[]用来表示是否为素数,里面存放0或1来进行逻辑判断。
先筛选掉所有偶数
for (i = 3; i <= input; i++) {
if (i % 2 == 0) {
prime[i] = 0;
} else {
prime[i] = 1;
}
}
之后的思想是如果i是素数,那么i加任意个i的数则是合数。举一个30以内的例子:
i=3; 由于prime[3]=1, 把prime[6], [9], [12], [15], [18], [21], [24], [27], [30]标为0.
i=4; 由于prime[4]=0,不在继续筛法步骤。
i=5; 由于prime[5]=1, 把prime[10],[15],[20],[25],[30]标为0.
i=4; 由于prime[4]=0,不在继续筛法步骤。
i=5; 由于prime[5]=1, 把prime[10],[15],[20],[25],[30]标为0.
完整的算法:
void primeFilter()
{
long i, j, input;
printf("input a number:");
scanf("%li", &input);
int prime[input + 1];
prime[2] = 1;
for (i = 3; i <= input; i++) {
if (i % 2 == 0) {
prime[i] = 0;
} else {
prime[i] = 1;
}
}
for (i = 3; i <= sqrt(input); i++) {
if (prime[i]) {
for (j = i + i; j < input; j += i) {
prime[j] = 0;
}
}
}
for (i = 2; i <= input; i++) {
if (prime[i]) {
printf("%li\n", i);
}
}
}
如果输入的数不是很大的时候,那么其实三个算法效果差别不大,但是如果数很大,比如100000,那么输出结果的时间可以相差好几秒。而且筛选法的时间非常快。