人們就知道了一個方法可以不必用除法,
就可找出從2到N之間的所有質數。
假設我們有一個很神奇的篩子,我們可以給它一個數i,
它可以把i的所有倍數去掉。
請用這個方法求出2到N之間的所有質數。
注意:
要求2到N的質數的話,最多篩到N/2就可以停下來了。
因為大過N/2的數都不可能整除N。
(因為存在這樣的數的話,表示有一個質數小於2且整除N)
程式不可使用乘法或除法,只能用加或減,以求加快速度。
這個方法叫做Eratosthenes(人名)的篩法(Sieve Method)。
解:
首先我們建立陣列,x[0] = 3、x[1] = 5、x[2] = 7......
(因為2的倍數可以直接不用考慮,或者說一開始就篩掉了)
所以x[i] = 2i+3 = i + i + 3。
我們可以用標記來表示x[i]是KEPT(保留,定為1)或DELETED(篩去,定為0)。
當一個一個查過去,沒有被篩掉的必然是質數,
因為其之前不存在任何數可以篩掉這個數。
接下來我們就要考慮碰到x[i]的時候,要篩掉2i+3的倍數:
1(2i+3)、3(2i+3)、5(2i+3)、7(2i+3)、9(2i+3)....(2n+1)(2i+3) n=0,1,2,...
偶數的部分本來就不在裡面,
又因為自己不可以篩掉。
所以每次要增加2(2i+3)的值,
即陣列的索引值每次要增加2i+3。
我們依此來標記所有對應的索引值為篩去。
同時,如果只是要把範圍內的合成數篩掉而不計數,
理論上來說不需要篩到最後一個。這個部分留待延伸討論。
Code中其實可以用把KEPT和DELETED放在#define裡,
不過我不太喜歡這種用法,所以就算了XD
Code:
int Sieve(int* x, int n)
{
// cnt = 1 because we don't have 2 in the array.
int i, j, tmp, cnt = 1, KEPT = 1, DELETED = 0;
for(i = 0; i <= n; i++)
x[i] = KEPT;
for(i = 0; i <= n; i++)
{
if(x[i]) // If KEPT -> start to sieve
{
tmp = i+i+3; // Each time index moves 2i+3
cnt++; // prime count
for(j = i+tmp; j <= n ; j += tmp)
x[j] = DELETED;
}
}
return cnt;
}
主程式部分:
int main(int argc, char *argv[])
{
int i, k, count, n = 500;
int *x = (int*)malloc(sizeof(int)*(n+1));
count = Sieve(x, n);
printf("Total: %d prime(s)", count);
printf("\n%6d", 2);
for(i = 0, k = 2; i <= n; i++)
{
if(x[i]) // KEPT
{
if(k > 10)
{
printf("\n");
k = 1;
}
printf("%6d", 2*i+3);
k++;
}
}
printf("\n");
system("PAUSE");
free(x); x = 0;
return 0;
}
沒有留言:
張貼留言