对于任意正整数N,Eratosthenes筛法可表示如下:
第1步,找出小于等于√N的全部素数:p1、p2、p3、…pm。
第2步,在1~N中分别划去p1、p2、…pm全部倍数(除了他们自己本身)。
第2步完成后剩下的整数除1外就是不超过N的全部素数。
简而言之,筛选原理如下:对于一个正整数a<=N,如果素数p1、p2、…、pm(小于等于√N)都不整除a,则a是素数。
下面是C++的单链表实现:
#include <iostream>
#include<cmath>
using namespace std;
const int N(20);//设置所能求的最大数,这里为400
struct Node
{
int data;
Node *next;
};
class Eratosthenes
{
public:
Eratosthenes(int n);//将1-n按顺序生成单链表,头插法生成单链表
void Delete(Node *p);//删除p指向的节点的后一个结点
void sqrtN();//求n的平方根,并将小于√n的所有素数放入数组中
int Factorial(int n);//递归求阶乘
void De();//筛选出number中各素数的倍数,并删除,p,q指向相邻结点
void print();//输出所有素数
private:
int number[N],X,a;//储存小于√n的所有素数,X为传入的数,a记录数组实际长度
Node *p, *q,*head;
};
Eratosthenes::Eratosthenes(int n)
{
int x;
x = int(sqrt(n));
X = n;
Node *s;
head = new Node; head->next = NULL;
for (int i = X; i >=x; i--)//头插法生成单链表按升序排序
{
s = new Node;
s->data = i;
s->next = head->next;
head->next = s;
}
}
void Eratosthenes::Delete(Node *t)
{
Node *w;//配合t删除t后一个结点
w = t->next;
t->next = w->next;
delete w;
}
void Eratosthenes::sqrtN()
{
double x = sqrt(X);//sqrt()返回值为double类型
int t ,y=0;
t = int(x);//强制类型转换
a = 0;
for (int i =2 ; i < t; i++)
if (Factorial(i - 1) % i == (i - 1))//威尔逊定理判断素数
{
number[y++] = i;
a++;
}
}
void Eratosthenes::De()
{
for (int i = 0; i < a; i++)//筛选出单链表中为number数组中各值的倍数时的data值,并删除相应的结点
{
p = head; q = p->next;
while (q->next != NULL)
{
if ((q->data)%number[i] == 0)//筛选number[i]的倍数,并删除对应data值相应的结点
{
Delete(p);
q = p->next;
}
else
{
p = q; q = q->next;
}
}
}
}
int Eratosthenes::Factorial(int n)//递归函数求阶乘
{
if (n == 1)return 1;
return n * Factorial(n - 1);
}
void Eratosthenes::print()
{
int t = 1;//控制输出格式
for (int i = 0; i < a; i++)
cout << number[i] << '\t';//输出number数组中的值,这些值也是需要求的n以内的素数
cout << endl;
q = head->next;
while (q->next != NULL)//输出节点中筛选出number数组中各值的倍数后剩下的值,即n以内的素数
{
cout << q->data << "\t";
if (t == a) {cout << endl;t = 0;}//控制输出格式
q = q->next;
t++;
}
}
int main()
{
int n;
cout << "请输入N:(求N以内的所有素数)";
cin >> n;
Eratosthenes T(n);
T.sqrtN();
T.De();
T.print();
return 0;
}