C++质数区间
C++ prime numbers interval
我必须编写脚本来打印给定范围内的质数。 目前我正在使用以下脚本:
#include <iostream>
using namespace std;
int main()
{
int n,p,m;
cin>>n >> m;
int * arr;
arr= new int[m+1];
for (int i=0; i<=m; i++)
{
arr[i]=0;
}
for(int i=2;i<=m;i++){
if(arr[i]==0)
{ p=i;
for (int j=2;p*j<=m;j++)
{
arr[p*j]=1;
}
}
}
for(int i=n;i<=m;i++){
if(arr[i]==0)cout<<i<<endl;
}
delete[] arr;
return 0;
}
它适用于小输入(它将 1 打印为素数,但这很容易修复(。 但是,当我输入像 1999998973 和 1999999973 这样的数字时,它会崩溃并显示 bad_alloc
.
我知道我可能做了一个巨大的阵列,但我不知道如何修复它。 我尝试了不同的算法,但它真的很慢,我需要它在大约 2 秒左右的时间内打印数字。 有人有想法吗?
似乎适用于我从 2 到 500 查看的数字。它不会随着1999998973到1999999973范围并给出这些结果,我不知道它们是否正确:
1999999003199999901319999990491999999061199999908119999990871999999093199999909719999991171999999121199999915119999991711999999207199999921919999992711999999321199999937319999994231999999439199999949919999995531999999559199999957119999996091999999613199999962119999996431999999649199999965719999997471999999763199999977719999998111999999817199999982919999998531999999861199999987119999998731999999913199999992719999999431999999973
int n,p,m;
cout << "enter two numbers" << endl;
cin >> n >> m;
int size = (m - n) + 1;
int * arr = new int[size];
// initialize the array to all zeros
for (int i=0; i < size; i++)
{
arr[i]=0;
}
// loop once for the entire set of numbers from 2 to max value to
// multiply with (sqrt of top of range)
int max = sqrt(m);
for(int i = 2; i <= max ;i++)
{
p = i;
for (int j=2 ; p*j <= m ; j++)
{
if ( (p * j) >= n )
{
arr[(p*j) - n] = 1;
}
}
}
for(int i = 0; i < size; i++)
{
if ( arr[i]==0 )
cout << (i + n) << endl;
}
delete[] arr;
问题是数组的空间。
选项 1:您可以将数组缩小到范围的大小。 你获得了空间,但你有额外的计算,因为你必须考虑你的埃拉托斯滕筛子范围之外的所有数字。
选项 2:使用 bit 而不是 int 来压缩数据。 您可以使用vector<bool>
轻松做到这一点。
使用选项 2,您可以保持代码原样,只需将 arr 更改为:
vector<bool> arr(m+1);
您甚至可以通过以下方式节省初始化循环:
vector<bool>arr(m+1, false);
无论您采取什么选择,我都建议您用添加剂版本替换您的镭脂筛的内环:
for (int i = 2; i <= m; i++){
if (arr[i] == 0)
{
for (int j = i*2; j <= m; j+=i) // no p, no multiplication, just add i at each iteration
{
arr[j] = 1;
}
}
}
时间
节省空间会增加时间。 然而,我怀疑即使你有足够的记忆,你也会在 2 秒内得到如此巨大的数字的答案。如果您必须处理 2 000 000 000 个数字,则需要在最多 1 纳秒内处理每个数字,即一条 CPU 指令以满足您的期望。
我建议使用轮子分解来更改算法。
如提供的链接的第一段所述,您可以通过除以 2,3,5 来确定一个数字是否是素数,然后除以全等到模 30 的数字,直到该数字的平方根。
下面列出了一个这样的实现。通过以这种方式检查素数,您无需创建最多 m
的数组。您唯一需要的数组是 wheelOf30[]
。
#include <math.h>
static const bool wheelOf30[] = {
false, true, false, false, false, false, false, true, false, false, // 1, 7,
false, true, false, true, false, false, false, true, false, true, // 11, 13, 17, 19,
false, false, false, true, false, false, false, false, false, true // 23, 29.
};
bool isPrime(int num)
{
// first, modulo by 2, 3, and 5
if ((num % 2 == 0) || (num % 3 == 0) || (num % 5 == 0))
return false;
int rootNum = sqrt(num);
// and then, divide by the congruent numbers represented by wheel of 30
for (int i = 7; i <= rootNum; i += 2)
{
// divide the number with the ones congruency to modulo 30 is true
if (wheelOf30[ i % 30 ])
{
if (num % i == 0)
return false;
}
}
return true;
}
您的主程序如下所示:
#include <iostream>
extern bool isPrime(int num);
int main(int argc, const char * argv[])
{
int n, m;
cin >> n >> m;
for (int i=n; i<=m; ++i)
if (isPrime(i))
cout << i << endl;
}
- 算术序列与区间的最大重叠
- 线性丢番图方程 - 求给定区间内的解数和解
- 整数区间(或 int 数组)中每个数字的出现次数
- 如果"n"是"2019"的倍数并且不在区间"(a,b)"中,
- 给定一个整数 N>0,区间 [0, 2^N) 中有多少个整数正好有 N-1 个设置位?编写一个返回正确答案的简短函数
- 是否有更有效的方法来检查元素是否在给定的区间内
- 获取位于特定区间的已排序值列表的子列表的最短方法
- C++显示两个区间之间的数字的程序检查一个数字是否可以表示为两个素数的总和
- 如何测试某些数字是否沿区间均匀分布?
- 两个不相交区间最小总和
- UML 类图(操作区间)
- 用于在2个带符号整数区间之间进行除法的C++算法
- Opencv cv::垫子公差区间
- 在C++中将一个区间分成n个相等的部分
- 在给定两个区间列表的情况下,得到重叠区间的数量
- 二叉树中区间值的向量
- 基于区间的数据结构(类似于boost icl)
- 给定一个区间向量,输出区间内重叠次数最多的任意一个数字
- 找出特定区间内的素数
- 在区间[0,n-1]中生成k个唯一随机数