Контейнер vector
Вектор в STL — это аналог массива, контейнер, который позволяет осуществлять доступ к элементам по индексам. Вектор является шаблоном, и объявляется, как все остальные шаблоны.
Например, вектор целых чисел можно объявить так:
При таком создании вектор является «пустым», не содержащим элементов. Можно сразу же объявить вектор некоторого фиксированного размера, если задать конструктор, указав в конструкторе количество элементов вектора:
В этом случае значения элементов вектора будут нулевыми (а если элементами вектора являются не числа, а, например, строки или другие структуры данных, то элементы вектора будут принимать значения по умолчанию, то есть строки и вложенные вектора будут пустыми). При необходимости можно сразу же заполнить вектор некоторыми (одинаковыми), значениями, указав их в качестве второго параметра конструктора, например, для заполнения вектора значениями -1 можно его объявить так:
Для использования контейнера vector необходимо подключить заголовочный файл vector:
Обращение к элементам вектора
К элементам вектора можно обращаться по индексу, например, так: A[i] .
Есть и другой способ обращения к элементу вектора с индексом i: использование метода at: A.at(i) . Отличие метода at от обращения при помощи квадратных скобок в том, что при использовании метода at происходит проверка правильности индекса, и в случае выхода за границы вектора происходит ошибка исполнения. Это полезно при отладке программ.
При обращении к элементам вектора при помощи квадратных скобок корректность индекса не проверяется, и в случае выхода за границы вектора дальнейшее поведение программы может быть непредсказуемым.
Следует отметить, что работа с элементами вектора осуществляется медленнее, чем с элементами массива (даже при использовании квадратных скобок, то есть без проверки выхода за границы массива).
Помимо этого у вектора есть метод front(), возвращающий ссылку на первый элемент и метод back(), возвращающий ссылку на последний элемент вектора.
Изменение размера вектора
Размер вектора можно узнать при помощи универсального метода size(), возвращающего для всех контейнеров в STL их размер. Также есть метод empty(), возвращающий логическое значение (true, если вектор пустой).
Размер вектора можно изменить в любой момент, при помощи метода resize. У этого метода может быть один или два параметра. Вызов метода resize(n) изменяет размер вектора до n элементов (длина вектора может как уменьшится, так и увеличиться). Вызов метода resize(n, val) изменяет размер вектора до n элементов, и если при этом размер вектора увеличивается, то новые элементы получают значение, равное val.
Очень часто бывает полезно добавлять элементы в конец вектора по одному и удалять элементы из конца вектора по одному. Для добавления нового элемента, равного val, в конец вектора, используется метод push_back(val). Для удаления последнего элемента вектора используется метод pop_back() — он не возвращает значения.
Добавление элемента в конец вектора осуществляется в среднем за O(1). Это реализовано за счет того, что память для хранения элементов вектора выделяется «с запасом», то есть можно будет добавлять элементы по одному, пока не кончится запас памяти. Если запас памяти исчерпан, выделяется новая память, при этом «запас» размера вектора удваивается.
Очистить вектор можно при помощи метода clear().
Вставка и удаление элементов в середину вектора
Метод erase позволяет удалять из середины вектора один или несколько элементов. Этот метод работает с итераторами. Подробней про его использование можно прочитать в документации.
Метод insert позволяет вставлять в середину вектора новый элемент, или несколько равных элементов, или другой вектор, или фрагмент другого вектора. Этот метод также работает с итераторами и про его использование можно прочитать в документации.
Поскольку вставка и удаление элементов требуют сдвига других элементов вектора, эти операции имеют линейную сложность, то есть выполняются за время, пропорциональное длине вектора.
Присваивание и сравнение векторов
Содержимое одного вектора можно целиком скопировать в другой вектор при помощи операции присваивания: A = B .
Также вектора можно сравнивать на равенство и неравенство ( A == B , A != B ), и сравнивать их содержимое в лексикографическом порядке ( A < B , A B , A >= B ).
Создание многомерных векторов
Элементами вектора могут быть и другие вектора. Например, можно сделать вектор, каждый элемент которого представляет собой вектор целых чисел:
Тем самым, a[i] будет вектором целых чисел, а обращаться к j-му элементу вектора a[i] можно через a[i][j].
Чтобы создать двумерный вектор размером n×m можно внешний вектор объявить размером n, а затем в цикле изменить размер каждого вложенного вектора:
for (int i = 0; i < n; ++i)
a[i].resize(m);
Но можно сделать это и в одну строку, если передать вторым параметром для конструктора вектора конструктор, который создает вектор целых чисел длины m:
Заметим, что размеры вложенных векторов могут изменяться и быть различными.
Также можно создавать вектор из стеков, очередей, деков, можно создавать трехмерные векторы и т.д.
Как проверить что вектор пустой c
Чаще всего требуется использовать массивы неопределенного размера. В таких случаях будет затратно использовать обычный массив, и выделять фиксированный объем памяти для него. Именно поэтому для таких целей подойдет вектор (vector).
Для использования векторов необходимо включить соответствующий заголовок и объявление using.
#include using std::vector;
Вектор является контейнером, поскольку он содержит другие объекты. При его использовании необходимо указать тип создаваемого значения. Ниже показаны примеры создания трех пустых векторов:
vector vec1; //vec1 содержит объекты типа int vector vec2; //vec2 содержит объекты типа string vector vec3; //вектор, содержащий другие вектора
Пустой вектор может показаться бесполезным, однако элементы в него можно добавлять и во время выполнения.
| Способы инициализации векторов | |
|---|---|
| vector v1 | Вектор, содержащий объекты типа T |
| vector v2(v1) | Вектор v2 — копия всех элементов вектора v1 |
| vector v2 = v1 | Эквивалент v2(v1), v2 — копия элементов вектора v1 |
| vector v3(n, val) | Вектор v3 содержит n элементов со значением val |
| vector v4(n) | Вектор v4 содержит n элементов типа T, инициализированного значением по умолчанию |
| vector v5 | Вектор v5 содержит столько элементов, сколько предоставлено инициализаторов |
| vector v5 = | Эквивалент v5 |
Все элементы вектора должны иметь один тип создаваемых значений.
Следует различать инициализацию с разными скобками () и <> .
В случае использования int
vector v1(10); //v1 имеет десять элементов со значением 0 vector v2; //v2 имеет один элемент со значением 10 vector v3(10, 1); //v3 имеет 10 элементов со значением 1 vector v4; //v4 имеет два элемента со значениями 10 и 1
В случае использования string
vector v5; //v5 имеет 1 элемент (списочная инициализация) vector v6("hi"); //ошибка, нельзя создать вектор из строкового литерала vector v7; //v7 имеет 10 элементов со значением по умолчанию vector v8(10, "hi"); //v8 имеет 10 элементов со значением "hi"
Если необходимо создать вектор со значениями от 0 до 9, то можно легко использовать списочную инициализацию. Но что же делать, если необходимы элементы от 0 до 99 или от 0 до 999? Списочная инициализация будет слишком громоздкой. В таком случае необходимо создать пустой вектор и использовать функцию push_back() , чтобы добавлять элементы во время выполнения.
Функция push_back() вставляет переданное ей значение в вектор как новый последний элемент. Например:
vector vec1; //пустой вектор for (int i = 0; i < 100; i++) vec1.push_back(i) //по завершении цикла vec1 имеет 100 элементов со значениями от 0 до 99
Этот же подход используется, когда необходимо создать вектор, количество элементов которого до времени выполнения неизвестно. Например, в вектор можно читать введенные пользователем значения.
string word; vector text; //пустой вектор while (cin >> word) < text.push_back(word); //добавить word в text >
Как проверить что вектор пустой c
Для добавления элементов в вектор применяется функция push_back() , в которую передается добавляемый элемент:
#include #include int main() < std::vectornumbers; // пустой вектор numbers.push_back(5); numbers.push_back(3); numbers.push_back(10); for(int n : numbers) cout << n << "\t"; // 5 3 10 std::cout
Векторы являются динамическими структурами в отличие от массивов, где мы скованы его заданым размером. Поэтому мы можем динамически добавлять в вектор новые данные.
Функция emplace_back() выполняет аналогичную задачу - добавляет элемент в конец контейнера:
std::vector numbers< 1, 2, 3, 4, 5 >; numbers.emplace_back(8); // numbers = < 1, 2, 3, 4, 5, 8 >;
Добавление элементов на определенную позицию
Ряд функций позволяет добавлять элементы на определенную позицию.
- emplace(pos, value) : вставляет элемент value на позицию, на которую указывает итератор pos
- insert(pos, value) : вставляет элемент value на позицию, на которую указывает итератор pos, аналогично функции emplace
- insert(pos, n, value) : вставляет n элементов value начиная с позиции, на которую указывает итератор pos
- insert(pos, begin, end) : вставляет начиная с позиции, на которую указывает итератор pos, элементы из другого контейнера из диапазона между итераторами begin и end
- insert(pos, values) : вставляет список значений начиная с позиции, на которую указывает итератор pos
std::vector numbers< 1, 2, 3, 4, 5 >; auto iter = numbers.cbegin(); // константный итератор указывает на первый элемент numbers.emplace(iter + 2, 8); // добавляем после второго элемента numbers = < 1, 2, 8, 3, 4, 5>;
std::vector numbers1< 1, 2, 3, 4, 5 >; auto iter1 = numbers1.cbegin(); // константный итератор указывает на первый элемент numbers1.insert(iter1 + 2, 8); // добавляем после второго элемента //numbers1 = < 1, 2, 8, 3, 4, 5>; std::vector numbers2 < 1, 2, 3, 4, 5 >; auto iter2 = numbers2.cbegin(); // константный итератор указывает на первый элемент numbers2.insert(iter2 + 1, 3, 4); // добавляем после первого элемента три четверки //numbers2 = < 1, 4, 4, 4, 2, 3, 4, 5>; std::vector values < 10, 20, 30, 40, 50 >; std::vector numbers3 < 1, 2, 3, 4, 5 >; auto iter3 = numbers3.cbegin(); // константный итератор указывает на первый элемент // добавляем после первого элемента три первых элемента из вектора values numbers3.insert(iter3 + 1, values.begin(), values.begin() + 3); //numbers3 = < 1, 10, 20, 30, 2, 3, 4, 5>; std::vector numbers4 < 1, 2, 3, 4, 5 >; auto iter4 = numbers4.cend(); // константный итератор указывает на позицию за последним элементом // добавляем в конец вектора numbers4 элементы из списка < 21, 22, 23 >numbers4.insert(iter4, < 21, 22, 23 >); //numbers4 = < 1, 2, 3, 4, 5, 21, 22, 23>;
Удаление элементов
Если необходимо удалить все элементы вектора, то можно использовать функцию clear :
std::vector v < 1,2,3,4 >; v.clear();
Функция pop_back() удаляет последний элемент вектора:
std::vector v < 1,2,3,4 >; v.pop_back(); // v =
Если нужно удалить элемент из середины или начала контейнера, применяется функция std::erase() , которая имеет следующие формы:
- erase(p) : удаляет элемент, на который указывает итератор p. Возвращает итератор на элемент, следующий после удаленного, или на конец контейнера, если удален последний элемент
- erase(begin, end) : удаляет элементы из диапазона, на начало и конец которого указывают итераторы begin и end. Возвращает итератор на элемент, следующий после последнего удаленного, или на конец контейнера, если удален последний элемент
std::vector numbers1 < 1, 2, 3, 4, 5, 6 >; auto iter = numbers1.cbegin(); // указатель на первый элемент numbers1.erase(iter + 2); // удаляем третий элемент // numbers1 = < 1, 2, 4, 5, 6 >std::vector numbers2 = < 1, 2, 3, 4, 5, 6 >; auto begin = numbers2.cbegin(); // указатель на первый элемент auto end = numbers2.cend(); // указатель на последний элемент numbers2.erase(begin + 2, end - 1); // удаляем с третьего элемента до последнего // numbers2 =
Также начиная со стандарта С++20 в язык была добавлена функция std::erase() . Она не является частью типа vector. В качестве первого параметра она принимает вектор, а в качестве второго - элемент, который надо удалить:
std::vector numbers3 < 1, 2, 3, 1, 5, 6 >; std::erase(numbers3, 1); // numbers3 =
В данном случае удаляем из вектора numbers3 все вхождения числа 1.
Размер вектора
С помощью функции size() можно узнать размер вектора, а с помощью функции empty() проверить, путой ли вектор:
#include #include int main() < std::vectornumbers; if(numbers.empty()) std::cout
С помощью функции resize() можно изменить размер вектора. Эта функция имеет две формы:
- resize(n) : оставляет в векторе n первых элементов. Если вектор содержит больше элементов, то его размер усекается до n элементов. Если размер вектора меньше n, то добавляются недостающие элементы и инициализируются значением по умолчанию
- resize(n, value) : также оставляет в векторе n первых элементов. Если размер вектора меньше n, то добавляются недостающие элементы со значением value
std::vector numbers1 < 1, 2, 3, 4, 5, 6 >; numbers1.resize(4); // оставляем первые четыре элемента - numbers1 = numbers1.resize(6, 8); // numbers1 =
Важно учитывать, что применение функции resize может сделать некорректными все итераторы, указатели и ссылки на элементы.
Изменение элементов вектора
Функция assign() позволяет заменить все элементы вектора определенным набором:
std::vector langs = < "Java", "JavaScript", "C">; langs.assign(4, "C++"); // langs =
В данном случае элементы вектора заменяются набором из четырех строк "C++".
Также можно передать непосредственно набор значений, который заменит значения вектора:
std::vector langs< "Java", "JavaScript", "C">; langs.assign(< "C++", "C#", "C">); // langs =
Еще одна функция - swap() обменивает значения двух контейнеров:
std::vector clangs < "C++", "C#", "Java" >; std::vector ilangs < "JavaScript", "Python", "PHP">; clangs.swap(ilangs); // clangs = < "JavaScript", "Python", "PHP">; for(std::string lang : clangs)
Сравнение векторов
Векторы можно сравнивать - они поддерживают все операции сравнения: , =, ==, !=. Сравнение контейнеров осуществляется на основании сравнения пар элементов на тех же позициях. Векторы равны, если они содержат одинаковые элементы на тех же позициях. Иначе они не равны:
std::vector v1 ; std::vector v2 ; std::vector v3 ; bool v1v2 = v1 == v2; // true bool v1v3 = v1 != v3; // true bool v2v3 = v2 == v3; // false
Векторы в C++: для начинающих

Всем привет! До этого дня мы использовали чистые массивы. Чистые - это значит простые массивы, не имеющие у себя в багаже различных функций. В этом уроке мы пройдем нечистые массивы - векторы.
Что такое вектор (vector)
Вектор - это структура данных, которая уже является моделью динамического массива.
Давайте вспомним о том, что для создания динамического массива (вручную) нам нужно пользоваться конструктором new и вдобавок указателями. Но в случае с векторами всего этого делать не нужно. Вообще, по стандарту пользоваться динамическим массивом через конструктор new - не есть правильно. Так как в компьютере могут происходить различные утечки памяти.
Как создать вектор (vector) в C++
Сначала для создания вектора нам понадобится подключить библиотеку - , в ней хранится шаблон вектора.
#include
Кстати, сейчас и в будущем мы будем использовать именно шаблон вектора. Например, очередь или стек, не созданные с помощью массива или вектора, тоже являются шаблонными.
Далее, чтобы объявить вектор, нужно пользоваться конструкцией ниже:
vector тип данных > имя вектора>;
- Вначале пишем слово vector .
- Далее в угольных скобках указываем тип, которым будем заполнять ячейки.
- И в самом конце указываем имя вектора.
vector string> ivector;
В примере выше мы создали вектор строк.
Кстати, заполнить вектор можно еще при инициализации (другие способы мы пройдем позже - в методах вектора). Делается это также просто, как и в массивах. Вот так:
vectorint> ivector = элемент[0]>, элемент[1]>, элемент[2]>>;
После имени вектора ставим знак равенства и скобки, в которых через пробел указываем значение элементов.
Такой способ инициализации можно использовать только начиная с C++11!
Так, чтобы заполнить вектор строками, нам нужно использовать кавычки - "строка" .
Второй способ обратиться к ячейке
Мы знаем, что в векторе для обращения к ячейке используются индексы. Обычно мы их используем совместно с квадратными скобками [] .
Но в C++ есть еще один способ это сделать благодаря функции - at(). В скобках мы должны указать индекс той ячейки, к которой нужно обратиться.
Вот как она работает на практике:
vector int> ivector = 1, 2, 3>; ivector.at(1) = 5; // изменили значение второго элемента cout . at(1); // вывели его на экран
Давайте запустим эту программу:
5 Process returned 0 (0x0) execution time : 0.010 s Press any key to continue.
Как указать количество ячеек для вектора
Указывать размер вектора можно по-разному. Можно это сделать еще при его инициализации, а можно хоть в самом конце программы. Вот, например, способ указать длину вектора на старте:
vector int> vector_first(5);
Так в круглых скобках () после имени вектора указываем первоначальную длину. А вот второй способ:
vector int> vector_second; // создали вектор vector_second.reserve(5); // указали число ячеек
Первая строчка нам уже знакома. А вот во второй присутствует незнакомое слово - reserve , это функция, с помощью которой мы говорим компилятору, какое количество ячеек нам нужно использовать.
Вы можете задать логичный вопрос: “А в чем разница?“. Давайте создадим два вектора и по-разному укажем их количество ячеек.
#include #include // подключили библиотеку using namespace std; int main() setlocale(0, ""); vector int> vector_first(3); // объявили // два vector int> vector_second; // вектора vector_second.reserve(3); cout <"Значения первого вектора (с помощью скобок): "; for (int i = 0; i 3; i++) cout [ i] <" "; > cout <"Значения второго вектора (с помощью reserve): " ; for (int i = 0; i 3; i++) cout [ i] <" "; > system("pause"); return 0; >
Значения первого вектора (с помощью скобок): 0 0 0 Значения второго вектора (с помощью reserve): 17 0 0 Process returned 0 (0x0) execution time : 0.010 s Press any key to continue.
Как видим, в первом случае мы вывели три нуля, а во втором: 17, 0, 0.
Все потому, что при использовании первого способа все ячейки автоматически заполнились нулями.
При объявлении чего-либо (массива, вектора, переменной и т.д) мы выделяем определенное количество ячеек памяти, в которых уже хранится ненужный для ПК мусор. В нашем случае этим мусором являются числа.
Поэтому, когда мы вывели второй вектор, в нем уже находились какие-то рандомные числа - 17, 0, 0. Обычно они намного больше. Можете кстати попробовать создать переменную и вывести ее значение.
Нужно помнить! При использовании второго способа есть некоторый плюс - по времени. Так как для первого способа компилятор тратит время, чтобы заполнить все ячейки нулями.
Как сравнить два вектора
Если в середине программы нам понадобится сравнить два массива, мы, конечно, используем цикл for и поочередно проверим все элементы.
Вектор опять на шаг впереди! Чтобы нам сравнить два вектора, потребуется применить всего лишь оператор ветвления if.
if (vec_first == vec_second) // сравнили! cout <"Они равны!"; > else cout <"Они не равны"; >
Конечно, компилятор все равно прогонит эти два вектора по циклу, проверяя ячейки. Но оцените, насколько благодаря этому программа стала компактнее. Разве это не прекрасно?
Вот так бы выглядела программа выше, если бы мы не использовали знак равенства для векторов.
bool flag = true; if (vec_first.size() == vec_second.size()) for (int i = 0; i vec_first.size(); i++) if (vec_first[i] != vec_second[i]) cout <"Они не равны!"; flag = false; break; // выходим из цикла > > > else flag = false; cout <"Они не равны!"; > if (flag) cout <"Они равны!"; >
- Сначала мы создали булеву переменную flag равную true . У нее задача такая:
- Если в условии (строки 5 - 10) она станет равна false - то значит эти векторы не равны и условие (строки 14 - 16) не будет выполняться.
- Если же она после цикла (строки 3 - 12) останется равна true - то в условии (строки 14 - 16) мы сообщим пользователю, что они равны.
- В условии (строка 3) проверяем размеры двух векторов на равенство.
- И если условие (строки 5 - 10) будет равно true - то мы сообщим пользователю, что эти два вектора не равны.
Как создать вектор векторов
Понятно, что вам может понадобиться записать числа в двумерный массив. Но зачем использовать массив, если можно оперировать векторами.
Сейчас вы узнаете, как создать вектор векторов или простым языком массив векторов.
vector vector тип данных > >;
Как можно увидеть, нам пришлось только добавить слова vector и еще его .
А чтобы указать количество векторов в векторе, нам потребуется метод resize() .
vector vector int> > vec; vec.resize(10); // десять векторов
Но есть еще одни способ добавления векторов в вектор. Для этого способа мы будем использовать функцию push_back() (читайте ниже, что она делает).
vec.push_back(vector int>());
- В аргументах функции push_back() находится имя контейнера, который мы хотим добавить. В нашем случае - vector .
- А дальше идет тип контейнера - .
- И все заканчивается отрывающей и закрывающей скобкой () .
Для двумерного вектора тоже можно указать значения еще при инициализации:
vector vector int> > ivector = 1, 4, 7>, 2, 5, 8>, 3, 6, 9>>;
- это значения элементов первого массива (первого слоя). Такие блоки значений, как , должны разделяться запятыми.
Методы для векторов:
Сейчас мы разберем некоторые методы, которые часто используются вместе с векторами. Метод - это функция, которая относится к определенному STL контейнеру.
В нашем случае этим STL контейнером является вектор. Если вы дальше собираетесь оперировать векторами - лучше все перечисленные функции запомнить.
Если нам требуется узнать длину вектора, понадобится функция - size() . Эта функция практически всегда используется вместе с циклом for.
for (int i = 0; i ivector.size(); i++) // . >
Также, если нам требуется узнать пуст ли стек, мы можем использовать функцию - empty() .
- При отсутствии в ячейках какого-либо значения это функция возвратит - true .
- В противном случае результатом будет - false .
Вот пример с ее использованием:
if (ivector.empty()) // . >
2) push_back() и pop_back()
Как мы сказали выше, у векторов имеются методы, которые помогают оптимизировать и улучшить жизнь прог