C++;优化该算法 在看过Terence Tao的一些视频之后,我想尝试将算法应用到C++代码中,找出所有的质数达到N个数。在我的第一个版本中,我只是测试了从2到n的每个整数,看看它们是否可以被从2到sqrt(n)的任何东西整除,我让程序在52秒内找到1到10000000之间的素数

C++;优化该算法 在看过Terence Tao的一些视频之后,我想尝试将算法应用到C++代码中,找出所有的质数达到N个数。在我的第一个版本中,我只是测试了从2到n的每个整数,看看它们是否可以被从2到sqrt(n)的任何东西整除,我让程序在52秒内找到1到10000000之间的素数,c++,algorithm,math,optimization,C++,Algorithm,Math,Optimization,为了优化程序,并实现我现在知道的埃拉托什尼筛,我假设任务完成的速度会比51秒快得多,但遗憾的是,事实并非如此。即使达到1000000也需要相当长的时间(尽管没有计时) #包括 #包括 使用名称空间std; void main() { 向量tosieve={}; 对于(int i=2;i向量{ 自动筛选=向量{}; 复制if(开始(至视图)、结束(至视图)、背面插入器(已筛选), [](int i)->bool{return i!=0;}); 回流筛分; }); 编辑: 还有另一种方法可以做到这

为了优化程序,并实现我现在知道的埃拉托什尼筛,我假设任务完成的速度会比51秒快得多,但遗憾的是,事实并非如此。即使达到1000000也需要相当长的时间(尽管没有计时)

#包括
#包括
使用名称空间std;
void main()
{
向量tosieve={};
对于(int i=2;i<1000001;i++)
{                                       
向后推(i);
}                                       
对于(int j=0;j//cout大多数
vector
操作,包括
erase()
具有
O(n)
线性时间复杂度

由于有两个大小为
10^6
的循环和一个大小为
10^6
vector
,因此您的算法最多执行
10^18
操作

用于如此大的
N
的Qubic算法将花费大量时间。
N
=
10^6
甚至可以用于二次算法


请仔细阅读。事实上,Eratosthenes算法的完全搜索和筛选都花费了相同的时间,这意味着第二个操作是错误的。

问题是“擦除”将向量中的每个元素向下移动一个,这意味着这是一个O(n)操作

有三种选择:

1) 只需将删除的元素标记为“空”(例如,将它们设为0)。这意味着未来的传递必须传递这些空位置,但这并不昂贵

2) 创建一个新向量,然后
将_向后推
新值


3) 使用std::remove\u if:这将向下移动元素,但在一次传递中执行此操作将更有效。如果使用std::remove\u if,则必须记住它不会调整向量本身的大小。

我在这里看到两个性能问题:

首先,
push_back()
必须偶尔重新分配动态内存块。使用
reserve()

考虑使用标准算法而不是手工编写的循环。它们帮助您陈述您的意图。在这种情况下,我看到
std::transform()
用于筛子的外循环,
std::any_of()
用于内循环,
std::generate_n()
用于填充
tosieve
,以及
std::copy_if())
用于填充
筛选的
(未测试的代码):

vector-tosieve={};
tosieve.resreve(1000001);
生成\u n(返回\u插入器(tosieve),1000001,[]()->int{
静态int i=2;返回i++;
});
转换(开始(tosieve)、结束(tosieve)、开始(tosieve),[](inti)->int{
返回(begin(tosieve)、begin(tosieve)+i-2、,
[&i](int j)->bool{
返回j!=0&&i%j==0;
})?0:i;
});
交换(tosieve,[&tosieve]()->向量{
自动筛选=向量{};
复制if(开始(至视图)、结束(至视图)、背面插入器(已筛选),
[](int i)->bool{return i!=0;});
回流筛分;
});
编辑:

还有另一种方法可以做到这一点:

vector<int> tosieve = {};
tosieve.resreve(1000001);
generate_n(back_inserter(tosieve), 1000001, []() -> int {
    static int i = 2; return i++;
});
swap(tosieve, [&tosieve]() -> vector<int> {
    auto sieved = vector<int>{};
    copy_if(begin(tosieve), end(tosieve), back_inserter(sieved),
            [](int i) -> bool {
                return !any_of(begin(tosieve), begin(tosieve) + i - 2,
                               [&i](int j) -> bool {
                                   return i % j == 0;
                               });
            });
    return sieved;
});
vector-tosieve={};
tosieve.resreve(1000001);
生成\u n(返回\u插入器(tosieve),1000001,[]()->int{
静态int i=2;返回i++;
});
交换(tosieve,[&tosieve]()->向量{
自动筛选=向量{};
复制if(开始(至视图)、结束(至视图)、背面插入器(已筛选),
[](int i)->bool{
返回!任意(begin(tosieve),begin(tosieve)+i-2,
[&i](int j)->bool{
返回i%j==0;
});
});
回流筛分;
});

现在不再标记元素,我们不想事后复制,只想直接复制我们要复制的元素。这不仅比上面的建议快,而且更能说明目的。

请修复缩进。从向量末尾以外的任何位置擦除元素都很慢,是的。埃拉托斯尼的筛子可以es不测试可除性,它只使用加法。(你不需要知道任何算法来手动执行筛选。)优化:不要构建向量并删除非素数;从空向量开始并添加素数。
vector<int> tosieve = {};
tosieve.resreve(1000001);       
for (int i = 2; i < 1000001; i++) 
{                                       
    tosieve.push_back(i);               
}
for (auto& x : tosieve) {
    for (auto y = tosieve.begin(); *y < x; ++y) // this check works only in
                                                // the case of an ordered vector
        if (y != 0 && x % y == 0) x = 0;
}
{ // this block will make sure, that sieved will be released afterwards
    auto sieved = vector<int>{};
    for(auto x : tosieve)
        sieved.push_back(x);
    swap(tosieve, sieved);
} // the large memory block is released now, just keep the sieved elements.
vector<int> tosieve = {};
tosieve.resreve(1000001);
generate_n(back_inserter(tosieve), 1000001, []() -> int {
    static int i = 2; return i++;
});

transform(begin(tosieve), end(tosieve), begin(tosieve), [](int i) -> int {
    return any_of(begin(tosieve), begin(tosieve) + i - 2,
                  [&i](int j) -> bool {
                      return j != 0 && i % j == 0;
                  }) ? 0 : i;
});
swap(tosieve, [&tosieve]() -> vector<int> {
    auto sieved = vector<int>{};
    copy_if(begin(tosieve), end(tosieve), back_inserter(sieved),
            [](int i) -> bool { return i != 0; });
    return sieved;
});
vector<int> tosieve = {};
tosieve.resreve(1000001);
generate_n(back_inserter(tosieve), 1000001, []() -> int {
    static int i = 2; return i++;
});
swap(tosieve, [&tosieve]() -> vector<int> {
    auto sieved = vector<int>{};
    copy_if(begin(tosieve), end(tosieve), back_inserter(sieved),
            [](int i) -> bool {
                return !any_of(begin(tosieve), begin(tosieve) + i - 2,
                               [&i](int j) -> bool {
                                   return i % j == 0;
                               });
            });
    return sieved;
});