C ++ для пропуска элементов цикла вектора? - PullRequest
0 голосов
/ 14 сентября 2018

Мне поручено создать вектор чисел 'x' и найти простые числа в этом векторе, используя "Сито Эратосфена". Я перебрал вектор, чтобы заменить все не простые элементы на ноль. Затем я сделал цикл for, чтобы стереть все нули. Цикл стер большую часть нулей, но пропустил некоторые

vector<int> primes;
int userNum = 0; //variable for user to input the size of the vector
cout << "Enter your num, brah";
cin >> userNum;
for (int i = 2; i < userNum; i++) //creates a vector of numbers
{
    primes.push_back(i);
}


int j = 0; //variable to find non-primes

for (int p = primes[0]; p < primes.size(); p++) //loop to replace non-primes with zeros
{
    j = p+p;

    while (j < (primes.size() +2)) {



        replace(primes.begin(), primes.end(), j, 0);

        j+= p;

    }
}

for (int y = 0; y < primes.size(); y++) { //loop to erase the zeros from the vector
    cout << "y1 " << primes[y] << " ";   //cout simply just to find see what is going on
    if (primes[y] == 0) {
        primes.erase(primes.begin() +y);
        cout << "y2: " << y << endl;  //cout simply just to find see what is going on
    }

}

cout << "New Vector is: " << endl; //loop to print the vector
for (int l = 0; l < primes.size(); l++)
{

    cout << primes[l] << ", ";
}

Вывод, который я получаю: Новый Вектор это: 2, 3, 5, 7, 0, 11, 13, 0, 17, 19, 0, 23, 0, 0, 29, 31, 0, 0, 37, 0, 41, 43, 0, 47, 0, 0, 53, 0, 0, 59, 61, 0, 0, 67, 0, 71, 73, 0, 0, 79, 0, 83, 0, 0, 89, 0, 0, 0, 97, 0, Программа завершилась с кодом выхода: 0

Ответы [ 3 ]

0 голосов
/ 14 сентября 2018

одна проблема наверняка состоит в том, что вы собираетесь пропустить элементы, потому что когда вы удаляете что-либо из последовательности, индекс всего после того, как она падает, уменьшается на 1.

Я сделал упрощенную версию вашего кода удаления, которая просто пытается удалить каждый элемент из вектора:

string vecToStr(const vector<int> &foos) {
  std::stringstream result;
  std::copy(foos.begin(), foos.end(), std::ostream_iterator<int>(result, " "));
  return result.str();
}

int main() {
  vector<int> foos = { 0,1,2,3,4,5,6 };
  for (int y = 0; y < foos.size(); y++) { //loop to erase the zeros from the vector
    foos.erase(foos.begin() + y);
    cout << "foos is now: " << vecToStr(foos) << " y is " << y << "\n";
  }
  cout << "foos is now: " << vecToStr(foos) << "\n";
  char c;
  cin >> c;
}

Вот вывод:

foos is now: 1 2 3 4 5 6  y is 0
foos is now: 1 3 4 5 6  y is 1
foos is now: 1 3 5 6  y is 2
foos is now: 1 3 5  y is 3
foos is now: 1 3 5

Вы можете видеть, как удаляется 0-й элемент, затем элемент со значением 1 перемещается в индекс 0, но затем y становится 1, поэтому он пропускается, затем 2 удаляется в индексе 1, а 3 перемещается в индекс 2, и т.д.

Существует множество подходов к этому (см. Удаление элементов вектора внутри цикла ). Старомодный способ C сделать это - пойти с конца:

  int y = foos.size();
  while(y--) {
    foos.erase(foos.begin() + y);
    cout << "foos is now: " << vecToStr(foos) << " y is " << y << "\n";
  }
0 голосов
/ 14 сентября 2018

Другие ответы дают хорошие предложения - идиома удаления идиомы хорошо известна и полезна.

Однако исправить ваш код очень просто. Посмотрите на эту петлю

for (int y = 0; y < primes.size(); y++) { //loop to erase the zeros from the vector
    if (primes[y] == 0) {
        primes.erase(primes.begin() +y);
    }
}

Это можно исправить, просто не увеличивая y при удалении элемента.

for (int y = 0; y < primes.size(); /* no increment here */) { //loop to erase the zeros from the vector
    if (primes[y] == 0) {
        primes.erase(primes.begin() +y);
    } else {
      y++;
    }
}
0 голосов
/ 14 сентября 2018

Нет необходимости писать цикл для удаления элемента из вектора. Используйте стирание-удаление идиома

primes.erase(std::remove(primes.begin(), primes.end(), 0), primes.end());

Выше указано, что std :: remove перемещает элементы, которые не должны быть удалены, в «левую сторону» или в начало вектора, и возвращает итератор, который указывает на первый элемент, который быть удаленным "на правой стороне". Затем primes.erase() фактически удаляет элементы, которые нужно удалить из вектора, начиная с итератора, возвращенного из вызова std::remove.

Вы можете разбить инструкцию на две строки, если не уверены, как она работает:

// returns an iterator to where the elements to erase are to be removed
auto iter = std::remove(primes.begin(), primes.end(), 0);

// Now actually erase them, starting at iter
primes.erase(iter, primes.end());
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...