Я пытаюсь создать метод, в котором мне нужно удалить число из вектора целых чисел, и это число передается в качестве параметра. Проблема, с которой я столкнулся прямо сейчас, заключается в том, что когда я пытаюсь удалить один и тот же номер в последовательных позициях, удаляется только один из них.

Например:

Vector = (1, 2, 2, 3, 4, 5), и я хочу удалить цифру «2», результат будет:

Вектор = (1, 2, 3, 4, 5)

Но если номер не находится в последовательных позициях, метод работает нормально:

Vector = (1, 2, 3, 2, 4, 5) ---> удалить "2"

Вектор = (1, 3, 4, 5)

Код, который у меня есть, такой:

void deleteNumber(int n, vector<int> &numbers)
{
    bool hasEntered = false;

    int counter = 0;
    vector<int> deletedNumbers;

    for(unsigned i = 0; i < numbers.size(); i++)
    {
        if(numbers[i] != n)
        {
            counter++;
        }

        else
        {
            counter = 0;
            int counter2 = 0;
            bool deleted = false;

            for(unsigned j = 0; j < deletedNumbers.size() && deleted == false; j++) // Check if a number has been deleted before
            {
                if(deletedNumbers[j] != n)
                {
                    counter2++;
                }

                else
                {
                    deleted = true;
                    counter2 = 0;
                }
            }

            if(counter2 == (int) deletedNumbers.size()) // Remove the number if it hasn't been removed
            {
                deletedNumbers.push_back(n);
                for(unsigned k = 0; k<numbers.size(); k++)
                {
                    if(numbers[k]  == n)
                        numbers.erase(numbers.begin()+k);
                }

                counter2 = 0;
                hasEntered = true;
            }
        }
    }
}

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

Счетчики используются, чтобы определить, был ли элемент найден или нет. А также метод должен проверить, удалялся ли элемент раньше.

Если вы чего-то не понимаете, спросите меня.

Заранее спасибо :)

0
user3577336 6 Май 2014 в 04:39

6 ответов

Лучший ответ

Вы можете попробовать что-то вроде этого:

void deleteNumber(int n, vector<int> &numbers)
{
    vector<int>numbers_without_n;
    for(unsigned i = 0; i < numbers.size(); i++)
        if(numbers[i] != n)
            numbers_without_n.push_back(numbers[i]);

    numbers = numbers_without_n;
}
1
Andres 6 Май 2014 в 00:47

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

Это приведет к удалению всех экземпляров n; O (числа.размер ()):

void deleteNumber(int n, vector<int> &numbers) {
  int i = 0;
  for (int j = 0; j < numbers.size(); ++j) {
    if (numbers[j] != n) numbers[i++] = numbers[j];
  }
  numbers.resize(i);
}

Это приведет к удалению первого экземпляра n при каждом запуске; O (числа.размер ()):

void deleteNumber(int n, vector<int> &numbers) {
  int i = 0;
  for (int j = 0; j < numbers.size();) {
    if (numbers[j] == n) {
      for (++j; j < numbers.size() && numbers[j] == n; ++j) {
        numbers[i++] = numbers[j];
      }
    } else {
      numbers[i++] = numbers[j++];
    }
  }
  numbers.resize(i);
}

Это приведет к удалению первого экземпляра n; O (числа.размер ()):

void deleteNumber(int n, vector<int> &numbers) {
  int i = 0;
  for (int j = 0; j < numbers.size(); ++j) {
    if (numbers[j] == n) {
      for (++j; j < numbers.size(); ++j) {
        numbers[i++] = numbers[j];
      }
      break;
    }
    numbers[i++] = numbers[j];
  }
  numbers.resize(i);
}

Выберите то, что вам нужно.

Обратите внимание, что другие ответы, такие как ответ luk32, содержат более простой код (с использованием большего количества STL) для удаления первого экземпляра n.

Если вы хотите найти и исправить ошибку в своем коде, я рекомендую вам попытаться найти очень короткий вектор ввода, для которого он не работает, а затем выполнить пошаговое выполнение в отладчике.

1
pts 6 Май 2014 в 01:07

Вам не нужно иметь петлю внутри петли. Самый простой способ справиться с удалением - удалять по одному элементу за раз и понимать, что это будет означать, что вы не хотите увеличивать i при удалении элемента. Самый простой способ отменить приращение i в цикле for - сначала уменьшить его, используя --i. Итак, петля становится

  • Проверьте, соответствует ли элемент номеру
  • Если да, удалите элемент и уменьшите i.
0
The Dark 6 Май 2014 в 00:46

Используйте std :: remove и vector :: erase

#include <algorithm>

void deleteNumber(int n, vector<int>& numbers)
{
   numbers.erase(std::remove(numbers.begin(), numbers.end(), n), numbers.end());
}
0
PaulMcKenzie 6 Май 2014 в 00:47

Во-первых, я не уверен, для чего используются counter и counter2 - если они просто используются, чтобы определить, прошли ли вы итерацию до конца вектора, не найдя элемент, они вам не нужны.

Чтобы «проверить, был ли удален номер», вам просто нужна одна логическая переменная в самом верху метода, то есть вне области действия цикла for.

Я верю в следующее:

if(counter2 == (int) deletedNumbers.size()) // Remove the numbers if it hasn't been removed

Можно заменить на if (! удалено).

Итак, вот «фиксированная» версия, пытаясь максимально приблизиться к вашей существующей логике, основываясь на ваших комментариях к коду. Возможно, это не самая эффективная / элегантная реализация, однако я считаю, что видел другие ответы, в которых для достижения того же результата используются алгоритмы из библиотеки STL.

void deleteNumber(int n, vector<int> &numbers)
{
    bool deleted = false;

    for(unsigned i = 0; i < numbers.size(); i++)
    {
        if (numbers[i] == n)  // If we've found an instance of the number we're trying to delete
        {
            if (!deleted)  // Check if an instance has already been deleted
            {
                numbers.erase(numbers.begin() + i);  // Remove the number
                deleted = true;  // Flag that we have deleted an instance of the number
            }
        }
    }
}

В качестве альтернативы, вместо использования флага для «удалено», чтобы предотвратить удаление чисел после первого экземпляра, вы можете оптимизировать, просто вернувшись после удаления первого экземпляра - это предотвратит выполнение остальной части цикла.

0
Kevin Lam 6 Май 2014 в 01:00

Хорошо, поскольку очевидно, что std::vector::erase действительно существует, я бы использовал стандартный c++ особенности:

void deleteNumber(int n, vector<int> &numbers) {
 auto it = find(std::begin(numbers), std::end(numbers), n);
 if(it != numbers.end()) numbers.erase(it);
}

РЕДАКТИРОВАТЬ: Забыл, что end() не является допустимым аргументом для erase.

0
luk32 6 Май 2014 в 01:07