【问题标题】:Prime Number above 6 million质数超过 600 万
【发布时间】:2020-11-23 08:44:27
【问题描述】:

我在 Hackerrank 中解决了一个问题,问题是找到一个范围内的素数计数。由于使用常规方法面临超时,我使用了埃拉托色尼筛。除了两个隐藏的测试用例外,大多数测试用例都有效。我在 GDB 编译器中运行代码,发现代码只支持高达 600 万的值。我该怎么办?代码如下:

#include<cstring>
#include<cstdio>
#include <iostream>
#include <algorithm>
using namespace std;


void SieveOfEratosthenes(unsigned long long int a,unsigned long long int b) 
{ 
    unsigned long long int count=0; 
    bool prime[b+1]; 
    memset(prime, true, sizeof(prime)); 
  
    for (unsigned long long int p=2; p*p<=b; p++) 
    { 
        // If prime[p] is not changed, then it is a prime 
        if (prime[p] == true) 
        { 
            for (unsigned long long int i=p*p; i<=b; i += p) 
                prime[i] = false; 
        } 
    } 
  
    for (unsigned long long int p=a; p<b; p++) 
       if (prime[p] &&p!=1) 
           count++;
    cout<<count;
          
} 
  
int main() 
{ 
    unsigned long long int a,b;
    cin>>a>>b;
    SieveOfEratosthenes(a,b); 
    return 0; 
} 

【问题讨论】:

  • 对于大于 600 万的数字,什么会失败?
  • 也许不是问题,但bool prime[b+1];不是标准的c++。 Why aren't variable-length arrays part of the C++ standard?
  • 可能是函数栈溢出了,可以用vector代替bool数组bool prime[b+1];
  • 一个大小为 600 万的布尔数组(每个大小为 1 个字节)大约是 6Mb 的堆栈大小。你几乎肯定超过了堆栈限制。
  • 我想问一件事:您是否必须回答包含ab 的多个查询?

标签: c++ primes memset sieve-of-eratosthenes largenumber


【解决方案1】:

看起来像经典的堆栈溢出。 bool prime[b+1]; 分配在堆栈上,您已达到限制。

如果它在 Linux 上运行,则允许的最大堆栈大小通常总计约为 8MB 或更小,因此很有可能您刚刚超过了这个值。

将其移出堆栈,或执行位打包而不是完整的bool,它应该会再次正常工作。

【讨论】:

    【解决方案2】:

    您正在函数中创建一个 bool 数组,该数组将存储在堆栈中。在 Windows 上,堆栈的典型最大大小为 1MB,而在典型的现代 Linux 上为 8MB。您正在创建一个包含 600 万条记录的数组,将近 6MB。

    要解决这个问题,您可以创建一个vector 而不是数组,这将是堆中的stored

    【讨论】:

    • 次要 nitpick:向量可以在栈上,但它的数据在堆上
    • vector&lt;bool&gt; 可能有一些小问题,因为它是唯一的“打包”矢量类,但在这种情况下,这是一个好处。对于 600 万个布尔值,它只有 750 kB,实际上向量本身会从堆中分配这 750kB。
    • 感谢@idclev463035818 的建议,我添加了一个链接,可以深入解释您所指的概念。
    • 谢谢@MSalters,我不明白它只需要750kB,你能解释一下吗?
    • @DeepakPatankar: std::vector&lt;bool&gt; 没有bool[] 的内部表示,这就是缺少std::vector&lt;bool&gt;::data() 的原因。相反,它每个字节存储 8 个布尔值。 600 万 / 8 = 750.000。
    猜你喜欢
    • 1970-01-01
    • 2019-02-22
    • 1970-01-01
    • 1970-01-01
    • 2021-07-23
    • 2010-11-10
    • 2011-05-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多