vector::insert в C++ (с примерами)

Привет! Сегодня мы рассмотрим полезную функцию C++ связанную с векторами — vector::insert. Начнем с обзора, перейдем к правильному использованию, продемонстрируем примеры и закончим простой собственной реализацией для лучшего понимания этой функции.

Что такое vector::insert?

В C++, векторы являются частью Standard Template Library (STL) и действуют как динамические массивы. Вы можете добавлять элементы, удалять их и даже изменять их размер по своему усмотрению. Одной из ключевых операций для векторов является вставка элементов, и вот здесь vector::insert приходит на помощь.

Функция vector::insert позволяет добавить элемент или диапазон элементов на любую конкретную позицию в векторе, сдвигая существующие элементы.

Вот простой пример:

#include <iostream>
#include <vector>
using namespace std;

int main() {
    vector<int> vec = {10, 20, 30};
    vec.insert(vec.begin() + 1, 15);  // Вставляет 15 между 10 и 20

    for(int num : vec) {
        cout << num << " ";
    }

    return 0;
}

Запустив приведенный выше код, вы получите:

10 15 20 30

Функция vector::insert имеет несколько перегрузок. Давайте рассмотрим их подробнее.

Перегрузки vector::insert

1. Вставка одного элемента

Синтаксис:

iterator insert (iterator position, const value_type& val);

Здесь вы можете вставить одно значение val перед позицией, на которую указывает итератор.

2. Повторяющаяся вставка элементов

Синтаксис:

iterator insert (iterator position, size_type n, const value_type& val);

С помощью этой перегрузки вы можете вставить значение val n раз на указанную позицию.

Пример:

vector<int> vec = {10, 20, 30};
vec.insert(vec.begin() + 1, 3, 15);  // Вставляет три 15 между 10 и 20

Содержимое вектора:

10 15 15 15 20 30

3. Вставка из другого контейнера

Синтаксис:

iterator insert (iterator position, InputIterator first, InputIterator last);

Эта перегрузка позволяет вставить диапазон элементов из другого контейнера в вектор на указанной позиции.

4. Вставка с использованием списка инициализации

Синтаксис:

iterator insert (iterator position, initializer_list<value_type> il);

С помощью этой перегрузки вы можете напрямую использовать список инициализации для одновременной вставки нескольких элементов.

vector<int> vec = {10, 20, 30};
vec.insert(vec.begin() + 2, {40, 50, 60});  // Вставляет 40, 50, 60 перед 30

Содержимое вектора:

10 20 40 50 60 30

Как это работает внутри

Когда вы используете vector::insert, это может показаться простым, но за кулисами происходит многое. Давайте рассмотрим поближе:

  1. Проверка емкости: Сначала функция проверяет, достаточно ли места в векторе для размещения новых элементов. Если нет, происходит перевыделение памяти, что может сделать недействительными все итераторы, указывающие на вектор.

  2. Сдвиг элементов: Все элементы после точки вставки сдвигаются, чтобы освободить место для новых элементов.

  3. Вставка элементов: Новые элементы вставляются в освободившиеся пространство.

Важно знать, что использование vector::insert может повлиять на производительность, особенно если вы вставляете на позицию, отличную от конца. Это связано с необходимостью перемещения всех последующих элементов. Поэтому используйте его с осторожностью!

Собственная реализация vector::insert

Для лучшего понимания концепции давайте создадим упрощенную версию vector::insert:

#include <iostream>
#include <vector>
using namespace std;

template <typename T>
void customInsert(vector<T> &vec, int pos, T value) {
  // 1. Проверка допустимости позиции
  if (pos < 0 || pos > vec.size()) {
    return;  // Недопустимая позиция
  }
  
  // 2. Добавление элемента в конец
  vec.push_back(value);
  
  // 3. Перемещение элементов, начиная с конца и до указанной позиции
  for (int i = vec.size() - 1; i > pos; --i) {
    swap(vec[i], vec[i - 1]);
  }
}

int main() {
    vector<int> vec = {10, 20, 30};
    customInsert(vec, 1, 15);

    for (int num : vec) {
        cout << num << " ";
    }

    return 0;
}

Вывод:

10 15 20 30 

Этот пример показывает то, что происходит при вызове vector::insert. Однако настоящая реализация STL гораздо сложнее и оптимизирована гораздо лучше.

Заключение

vector::insert — это мощный инструмент для работы с векторами в C++. Он предлагает гибкость вставки элементов на любую позицию в векторе. Надеемся, что эта статья помогла вам лучше понять эту функцию и научиться правильно ее использовать.

Упражнения

  1. Базовое использование vector::insert:

    • Напишите программу на C++, создающую вектор строк.
    • Запросите у пользователя строку и позицию, на которой он хочет вставить эту строку.
    • Используйте функцию vector::insert, чтобы добавить строку на указанную позицию.
    • Покажите пользователю измененный вектор.
  2. Изучение перегрузок:

    • Доработайте предыдущую программу, предоставив пользователю несколько вариантов действий: а. Вставить одну строку на указанную позицию. б. Вставить строку несколько раз на определенную позицию. в. Вставить диапазон строк из другого вектора на выбранную позицию. г. Вставить, используя список инициализации.
    • Запросите у пользователя, какой из вариантов он хочет выбрать, и выполните соответствующее действие. Показывайте результирующий вектор после каждого изменения.
  3. Влияние на производительность:

    • Напишите программу на C++, демонстрирующую разницу в производительности при вставке элемента в начало и в конец большого вектора.
    • Создайте вектор размером 100 000, заполненный случайными числами.
    • Измерьте время, необходимое для вставки нового числа в начало и в конец вектора.
    • Покажите пользователю время, потраченное на каждую операцию. Размышляйте о причинах разницы во времени.

Обсуждение