求前N个质数

本文介绍了求解前N个质数的一种入门级标准方法,通过使用平方提高效率避免开方的精度问题。利用素数在6n±1的位置规律进行筛选,时间复杂度为O(N)。通过不断选择素数n、m和p,删除非素数,最终得到所需质数列表。
部署运行你感兴趣的模型镜像

入门级的标准解法如下:

#include <iostream>
#include <vector>

using namespace std;

vector<int> ivec;

bool isPrime(int number)
{
	bool result = true;

	for (int i = 2; i < number; i++)
	{
		if (number % i == 0)
		{
			result = false;
			break;
		}		
	}

	return result;
}

void generateNPrime(int N)
{
	int count = N;

	int number = 2;
	while (count)
	{
		if (isPrime(number) == true)
		{
			count--;
			ivec.push_back(number);
		}
		number++;
	}
}

void main()
{
	generateNPrime(100);
	copy(ivec.begin(), ivec.end(), ostream_iterator<int>(cout, " "));
}


有两个小小的改进地方就是对于for循环的判断上

bool isPrime(int number)
{
	bool result = true;

	for (int i = 2; i <= number >> 1; i++)
	{
		if (number % i == 0)
		{
			result = false;
			break;
		}		
	}

	return result;
}

bool isPrime(int number)
{
	bool result = true;

	for (int i = 2; i <= sqrt((double)(number)); i++)
	{
		if (number % i == 0)
		{
			result = false;
			break;
		}		
	}

	return result;
}

比起开方运算,更建议使用平方来求解,平方的效率更高,而且开方存在精度问题

bool isPrime(int number)
{
	bool result = true;

	for (int i = 2; i * i <= number; i++)
	{
		if (number % i == 0)
		{
			result = false;
			break;
		}		
	}

	return result;
}

先来看一下100以内的素数:

2 3 5 7 11 13 17...

我们可以看到素数的规律在5之后是2、4、2、4这样间隔着出现,但是会一直这样间隔出现吗,答案是否定的,但是非这样的间隔必然不是素数

因为6n, 6n+1, 6n+2, 6n+3, 6n+4, 6n+5,只有6n+1和6n+5需要检测是否为素数

所以可以做一定程度上的筛选:

void generateNPrime(int N)
{
	int count = N;

	int number = 5;
	ivec.push_back(2);
	ivec.push_back(3);
	ivec.push_back(5);
	count -= 3;
	int gap = 2;
	while (count)
	{
		number += gap;
		gap = 6 - gap;
		if (isPrime(number) == true)
		{
			count--;
			ivec.push_back(number);
		}
	}
}

时间复杂度为O(N)的素数筛选法!!!

原理如下:

1. 首选选取一个素数n

2. 选取素数m,m从n开始,依次选取下一个素数,跳出条件是n * m <= N

3. 选取素数p,p从m * n开始选取,每次*素数n,跳出条件是p * n <= N

删除

例如20以内的素数

2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,16, 17, 18, 19, 20

选取素数n,n = 2; 那么m = 2, p = 4;

开始remove p,循环下来,4, 8, 16全部被删除

m选取下一个数,选取3

remove p,循环下来,6, 12

m选取下一个数,选取5

remove p,循环下来,删除10, 20

m选取下一个数,选取7,删除14

m选取下一个数,选取9,删除18

第一重循环跳出,经过本轮筛选,剩下的数字为:

2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,16, 17, 18, 19, 20

重复上面的逻辑,再经过一轮筛选,不难得出剩下的数字为:

2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,15,16, 17, 18, 19, 20

两轮筛选后,循环跳出~

#include <iostream>

using namespace std;

#define MAXSIZE 1000
#define NEXT(x) x = next[x]
#define PREVIOUS(x) x = previous[x - 1]
#define  REMOVE(x) { next[PREVIOUS(x)] = next[x]; \
                      previous[next[x]] = previous[x]; }
#define INITIAL(n) { unsigned long i; \
						for (int i = 2; i <= n; i++) \
							previous[i] = i - 1, next[i] = i + 1; \
						previous[2] = next[n] = 0; \
					}

void main()
{
	unsigned long previous[MAXSIZE + 1];
	unsigned long next[MAXSIZE + 1];
	unsigned long prime, fact, i, mult;
	unsigned long n;
	unsigned long count = 0;
	printf("\nLinear Sieve Program");
	printf("\n====================");
	printf("\n\nPrime Numbers between 2 to --> ");
	scanf("%d", &n);
	INITIAL(n);
	for (prime = 2; prime * prime <= n; prime = next[prime])
		for (fact = prime; prime * fact <= n; fact = next[fact])
			for (mult = prime * fact; mult <= n; mult *= prime)
			{
				if (fact == 9)
					cout << "mult = " << mult << endl;
				next[previous[mult]] = next[mult];
				previous[next[mult]] = previous[mult]; 
			}

	for (int i = 2; i != 0; i = next[i])
	{
		if (count % 8 == 0)
			printf("\n");
		printf("%6ld", i);
		count++;
	}

	printf("\n\nThere are %ld Prime Numbers in Total", count);
}



您可能感兴趣的与本文相关的镜像

EmotiVoice

EmotiVoice

AI应用

EmotiVoice是由网易有道AI算法团队开源的一块国产TTS语音合成引擎,支持中英文双语,包含2000多种不同的音色,以及特色的情感合成功能,支持合成包含快乐、兴奋、悲伤、愤怒等广泛情感的语音。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值