我正在尝试在C ++中实现Sieve of Eratosthene。但是经过多次尝试后,我总是遇到运行时错误。我认为这与使用的迭代器状态在某处被破坏有关。我不能把手指放在它上面。这是我的代码:
//Sieves all multiples of the current sequence element
bool multiple_sieve(std::list<int>& num_list)
{
std::list<int>::iterator list_iter(num_list.begin());
std::list<int>::reverse_iterator last_element_iter(num_list.rbegin());
for(std::list<int>::iterator elements_iter(++list_iter);
elements_iter != num_list.end();)
{
if((*elements_iter % *list_iter == 0) &&
(*elements_iter <= *last_element_iter) && (*list_iter != 1))
num_list.erase(elements_iter);
else ++elements_iter;
}
return true;
}
std::list<int>& prime_sieve(std::list<int>& num_list)
{
for(std::list<int>::iterator list_iter(num_list.begin());
list_iter != num_list.end(); ++list_iter)
multiple_sieve(num_list);
return num_list;
}
我做错了什么?是什么导致了运行时错误?
更新:当我在测试中运行它时,我收到错误消息“列表迭代器不兼容”。
答案 0 :(得分:5)
这一行:
num_list.erase(elements_iter);
因为在迭代时修改列表会导致问题。你可以这样做以避免这个问题:
elements_iter = num_list.erase(elements_iter);
ETA:删除了擦除()使其他迭代器无效的东西(在这种情况下看起来很安全) - 只需将elements_iter设置为erase()的返回值,你就应该好了。
答案 1 :(得分:4)
我不知道你为什么在这里使用列表。在向量上运行筛子并在列表中保存质数更容易。
std::list<int> primes(int MAXN){
std::list<int> result;
std::vector<bool> sieve(MAXN+1,true);
for(int i=2;i<=MAXN;i++){
if(sieve[i]==true){
result.push_back(i);
if((long long)i*i<=MAXN) //prevent integer overflow
for(int j=i*i;j<=MAXN;j+=i)
sieve[j]=false;
}
}
return result;
}
答案 2 :(得分:3)
我想我看到一个问题,它是std :: list.erase()。 erase()使擦除的迭代器 无效 - 其他部分的所有迭代器都有效。删除后,继续在for语句中使用它 - “elements_iter!= num_list.end()”。
要解决这个问题,你可以使用erase()在擦除之后返回迭代器的事实,如果擦除的oiterator是最后一个,则返回结束。所以替换行:
<强> num_list.erase(elements_iter); 强>
通过
elements_iter = num_list.erase(elements_iter);
如果你还有问题,我建议你在Visual Studio下调试你的算法 - 它有debub版本的STL,所以如果出现错误,调试器会在线停止导致问题。
答案 3 :(得分:2)
num_list.erase(elements_iter)
我认为你不应该这样做,这会完全删除列表中的数字,你宁愿把它标记为非素数。
如果你真的想使用STL代替bool数组,最好像this implementation一样使用std :: bitset(好吧,也可能有更好的)。
答案 4 :(得分:2)
我发布了更有效的筛子previously。
这对我有用。来自代码的值得注意的修改:使用.erase(i++)
否则迭代器将失效,并从列表中的连续位置开始multiple_sieve
,而不是始终从头开始。
#include <iostream>
#include <list>
template<typename T, typename L>
void multiple_sieve(L &nums,
const typename L::iterator &begin, const typename L::iterator &end) {
T first = *begin;
typename L::iterator i(begin);
++i;
while (i != end)
if (*i % first == 0) nums.erase(i++);
else ++i;
}
template<typename T, typename L>
void prime_sieve(L &nums) {
typename L::iterator end = nums.end();
for (typename L::iterator i(nums.begin()); i != end; ++i)
multiple_sieve<T, L>(nums, i, end);
}
int main(int argc, char **argv) {
std::list<int> list;
for (int i = 2; i < 1000; i++)
list.push_back(i);
prime_sieve<int, std::list<int> >(list);
for (std::list<int>::iterator i(list.begin());
i != list.end(); i++)
std::cout << *i << std::endl;
}