簡體   English   中英

這種算法實現有什么問題[Erathosthene篩]

[英]What's wrong with this algorithm implementation [Sieve of Erathosthene]

我正在嘗試用C ++實現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;
    }

我做錯了什么? 什么導致運行時錯誤?

更新:當我在我的測試中運行它時,我收到錯誤消息“列表迭代器不兼容”。

這一行:

num_list.erase(elements_iter);

因為您在迭代時修改列表會導致問題。 您可以這樣做以避免該問題:

elements_iter = num_list.erase(elements_iter);

ETA:刪除了擦除()使其他迭代器失效的東西(在這種情況下看起來很安全) - 只需將elements_iter設置為erase()的返回值,你就應該好了。

我不知道你為什么在這里使用列表。 在向量上運行篩子並在列表中保存質數更容易。

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;
}

我想我看到一個問題,它是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,所以如果出現錯誤,調試器會在線停止導致問題。

num_list.erase(elements_iter)

我不認為你應該這樣做,這會完全刪除列表中的數字,你寧願把它標記為非素數。

如果你真的想使用STL代替bool數組,那么最好在這個實現中使用std :: bitset(好吧,也可能有更好的)。

我已經發布了一個更高效的篩


這適合我。 來自代碼的值得注意的修改:使用.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;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM