Видалити елемент з кінця вектора C++
У цьому пості ми обговоримо, як видалити елемент з кінця вектора C++. Рішення повинне ефективно зменшити розмір вектора на одиницю.
1. Використання std::vector::erase
Стандартне рішення для видалення елемента з вектора це std::vector::erase функція. Він переводить ітератор на позицію, де елемент потрібно видалити. Щоб видалити елемент у кінці вектора, передайте ітератор, який вказує на останній елемент у векторі.
Ось як виглядатиме код. Зауважте, що std::vector::end повертає ітератор не до останнього елемента вектора, а до останнього елемента.
Видалити векторний вміст та звільнити пам'ять у C++
У цьому пості ми обговоримо, як видалити вміст вектора та звільнити пам'ять, виділену вектором, для зберігання об'єктів у C++.
1. Використання vector::clear функція
Ми можемо використовувати vector::clear функція для видалення всіх елементів вектора. Він працює, викликаючи деструктор кожного векторного об'єкта, але основне сховище не звільняється. Отже, у нас залишився вектор нульового розміру, але з деякою кінцевою ємністю.
результат:
The vector size is 0, and its capacity is 5
Починаючи з C++11 ми можемо викликати vector::shrink_to_fit функціонувати після clear() , що зменшує здатність вектора збільшувати розмір. Він працює, “запитуючи” перерозподіл вектора.
результат:
The vector size is 0, and its capacity is 0
2. Використання vector::erase функція
Іншим рішенням є виклик vector::erase функцію на векторі, як показано нижче. Це також страждає від тієї ж проблеми, що й clear() функція, тобто. е. не гарантується перерозподіл пам'яті у векторі.
результат:
The vector size is 0, and its capacity is 0
3. Використання vector::resize функція
Ми також можемо використовувати vector::resize функцію зміни розміру вектора. Зауважте, що ця функція не знищує векторні об'єкти, і всі посилання на об'єкти залишаються дійсними.
результат:
The vector size is 0, and its capacity is 0
4. Використання vector::swap функція
Всі перераховані вище рішення не можуть звільнити пам'ять, виділену для векторного об'єкта, без виклику методу vector::shrink_to_fit функція. shrink_to_fit() зменшує ємність, щоб відповідати розміру, але ми не можемо повністю покладатися на це. Це з тим, що він робить необов'язковий запит, і реалізація вектора може його ігнорувати.
Існує ще один обхідний шлях звільнення пам'яті, зайнятої векторним об'єктом. Ідея полягає в тому, щоб замінити вектор порожнім вектором (без виділеної пам'яті). Це звільнить пам'ять, яку займає вектор, і завжди гарантовано працюватиме.
Як мені видалити елемент зі std::vector<> за індексом?
Насправді функція erase працює для двох профілів:
Видалення одного елемента
iterator erase (iterator position);
iterator erase (iterator first, iterator last);
Оскільки std::vec.begin() означає початок контейнера, і якщо ми хочемо видалити елемент ith у нашому векторі, ми можемо використовувати:
vec.erase(vec.begin() + index);
Якщо ви уважно подивіться, vec.begin() - це вказівник на початкову позицію нашого вектора, і додавання значення i до нього збільшує вказівник на позицію i . Таким чином, ми можемо отримати доступ до покажчика на i-ий елемент за допомогою &vec[i]:
vec.erase(&vec[i]); // To delete the ith element
Якщо у вас є невпорядкований вектор, ви можете скористатися тим, що він невпорядкований, і використовувати те, що я бачив від Дена Хіггінса в CPPCON
template < typename TContainer >статичний bool EraseFromUnorderedByIndex( TContainer& inContainer, size_t inIndex ) < if ( inIndex < inContainer.size() ) < if ( inIndex != inContainer.size() - 1 ) inContainer[in ; inContainer.pop_back(); return true; >return false; >
Оскільки порядок списку не має значення, просто візьміть останній елемент у списку та скопіюйте його на початок елемента, який ви хочете видалити, потім вставте та видаліть останній елемент.
Це може бути очевидним для деяких людей, але докладно розглянути вищевказані відповіді:
Якщо ви видаляєте елементи std::vector за допомогою erase у циклі по всьому вектору, ви повинні обробити свій вектор у зворотному порядку, тобто за допомогою
for (int i = v.size() - 1; i >= 0; i--)
Причина в тому, що індекси впливають на erase , тому якщо ви видалите 4 елемент, то колишній 5 елемент тепер є новим 4 елементом, і він не буде оброблятися вашим циклом, якщо ви використовуєте i + + .
Нижче наведено простий приклад, що ілюструє це, де хочу видалити всі елементи шансів у векторі int;
#include #include using namespace std; void printVector(const vector &v) < for (size_t i = 0; i < v.size(); i++) < cout cout int main() < vectorv1, v2; for (int i = 0; i < 10; i++) < v1.push_back(i); v2.push_back(i); >// print v1 cout = 0; i--) < if (v2[i] % 2 != 0) < cout else < cout > cout else < cout > return 0; >
v1: 0 1 2 3 4 5 6 7 8 9 v2: 0 1 2 3 4 5 6 7 8 9 --- Erase odd elements --- Process v2 with decreasing indices: # 8 # 6 # 4 # 2 # 0 Process v1 with increasing indices: 0 # # # # #
Зверніть увагу, що у другій версії зі збільшенням індексів навіть числа не відображаються, оскільки вони пропущені через i++
Зверніть увагу, що при зворотній обробці вектора, ви НЕ використовуєте беззнакові типи для індексів ( for (uint8_t i = v.size() -1;. не буде працювати). Це відбувається тому, що коли i дорівнює 0 , i- буде переповнений і дорівнює 255 для uint8_t , наприклад (так що цикл не зупиниться, оскільки i все ще буде >= 0 і, ймовірно, поза межами вектора).
Якщо ви працюєте з великими векторами (розмір > 100 000) і хочете видалити багато елементів, я б порекомендував зробити щось на зразок цього:
int main(int argc, char** argv) < vector vec; vector vec2; for (int i = 0; i < 20000000; i++)< vec.push_back(i);>for (int i = 0; i < vec.size(); i++) < if(vec.at(i) %3 != 0) vec2.push_back(i); > vec = vec2; cout
Код приймає кожне число у столітті, яке не можна розділити на 3, і копіює його в століття2. Після цього він копіює век2 у століття. Це досить швидко. Щоб обробити 20000000 елементів, цей алгоритм займає тільки 0.8 сек!
Я зробив те саме з методом erase, і це займає багато часу:
Erase-Version (10k елементів) : 0.04 sec Erase-Version (100k elements) : 0.6 sec Erase-Version (1000k elements): 56 sec Erase-Version (10000k elements): . still calculating (>30 min)
vec.erase(vec.begin() + 1, vec.begin() + 3);
З цим ви пратимете n -ий елемент vec , але перед тим, як ви пратимете другий елемент, все інші елементи vec будуть зсунуті, і розмір вектора буде зменшено на 1. Це може бути проблемою, тому що ви можете пройти циклом по vec , тоді як його size() зменшується .
Якщо у вас є така проблема, це посилання пропонує використовувати remove і remove_if .
Якщо вам потрібно стерти елемент усередині циклу for, зробіть таке:
Щоб видалити елемент, використовуйте такий спосіб:
// declaring and assigning array1 std:vector array1; // erasing the value in the array array1.erase(array1.begin()+n);
Для ширшого огляду ви можете відвідати: http://www.cplusplus.com/reference/vector/vector/erase/
Вам необхідно використовувати функцію std::vector::erase стандартної бібліотеки шаблонів.
Приклад: Видалення елемента з вектора (з використанням індексу)
// Deleting the eleventh element from vector vec vec.erase( vec.begin() + 10 );
Пояснення вищезазначеного коду
std::vector::erase Використання:
iterator erase (iterator position); // until C++11
iterator erase (const_iterator pos); // since C++11 і until C++20
constexpr iterator erase (const_iterator pos); // since C++20
Тут є один параметр position , який є ітератором, що вказує на один елемент, який потрібно видалити з вектора. Типи членів iterator та const_iterator є випадковими типами ітераторів, які вказують на елементи.
Як це працює
Функція erase робить таке:
- Вона видаляє з вектора або один елемент (position), або діапазон елементів ([first, last)).
- Це зменшує розмір контейнера на кількість видалених елементів, що знищуються.
Примітка: Ітератор pos повинен бути дійсним та детерференційним. Отже, ітератор end() (який дійсний, але з детерференцируем) не може бути використаний як значення для pos .
Значення, що повертається, і складність
Значення, що повертається - це ітератор, що вказує на нове місце розташування елемента, який слідував за останнім елементом, який був стертий при виклику функції. Це кінець контейнера операції, який стер останній елемент у послідовності.
Ітератор типу члена – це тип random access iterator, який вказує на елементи.
Тут складність часу лінійна кількості стертих елементів (руйнувань) плюс кількість елементів після видалення (переміщення) останнього елемента.
Ще один спосіб зробити це, якщо ви хочете видалити елемент, знайшовши його значення у векторі, вам просто потрібно зробити це для вектора.
vector ar(n); ar.erase(remove(ar.begin(), ar.end()), (place your value here from vector array));
це видалить ваше значення звідси. дякую
Попередні відповіді припускають, що у вас завжди є підписаний індекс. На жаль, std::vector використовує size_type для індексації та difference_type для ітераційної арифметики, тому вони не працюють разом, якщо у вас включено "-Wconversion" та друзі. Це ще один спосіб відповісти на питання, при цьому мати можливість обробляти як підписані, так і беззнакові:
template::value>::type> void remove(std::vector &v, I index) < const auto &iter = v.cbegin() + gsl::narrow_cast(Index); v.erase(iter); >
template::value>::type> T take(std::vector &v, I index) < const auto &iter = v.cbegin() + gsl::narrow_cast(Index); auto val = * iter; v.erase(iter); return val; >
найшвидший спосіб (для змагань із програмування за складністю часу() = константа)
може стерти 100M елементів за 1 секунду;
vector it = (vector::iterator) &vec[pos]; vec.erase(it);
і найчитанніший спосіб: vec.erase(vec.begin() + pos);