- std::vector служит для замены массивов. Подключается через #include <vector>;
- Вектор может менять размер в процессе выполнения программы (в отличие от статического массива)
- Всегда можно получить размер вектора через функцию size() (в отличие от динамического массива)
- Вектор автоматически уничтожается при выходе из области видимости (в отличии от динамического массива)
- Вектор передается в функцию по значению (изменения в функции вектора не изменяет его ) в отличие от массива, который передается по ссылке.
- Элементы вектора хранятся в непрерывной области памяти подряд (в куче).
Двумерный векторМетод | Описание | Пример | Сложность |
---|---|---|---|
[size_t index] | Доступ к элементу по индексу. | auto i = v.[20]; | O(1) |
assign(size_t size, const T& value) | Заменяет содержимое вектора на size элементов со значениями value | v.assign(3, 4); | O(n) |
assign(iterator it_start, iterator it_stop) | Заменяет содержимое вектора диапазоном значений из контейнера ограниченного итераторами | v.assign(ls.begin(), ls.end()); | O(n) |
assign(initializer_list<T> lst) | Заменяет содержимое вектора значениями заданными в списке | v.assign({3, 5, 7}); | O(n) |
at(size_t index) | Доступ к элементу по индексу. Выбрасывает исключение при выходе за границы. | auto i = v.at(20); | O(1) |
back() | Доступ к последнему элементу. | auto i = v.back(); | O(1) |
begin() | Возвращает итератор на первый элемент. | auto i = v.begin(); | O(1) |
capacity() | Возвращает количество элементов для добавления без реаллокации. | size_t i = v.capacity(); | O(1) |
clear() | Удаляет все элементы вектора. | v.clear(); | O(n) |
data() | Возвращает указатель на массив данных (не контейнер) | auto *i = v.data(); | O(1) |
emplace(iterator it, T value) | Вставляет значение value перед итератором it | v.emplace(v.begin(), 100); | O(n) |
emplace_back(T value) | Вставляет новый элемент со значением value в конце вектора | v.emplace_back(100); | O(1) |
empty() | Возвращает пустой ли вектор. | if(v.empty()); | O(1) |
end() | Возвращает итератор на место после последнего элемента. | auto i = v.end(); | O(1) |
erase(iterator pos) | Удаляет элемент(ы) из заданной позиции. | v.erase(v.begin() + 2); v.erase(v.begin() + 2, v.end()); | O(n) |
front() | Возвращает ссылку на первый элемент вектора. | auto i = v.front(); | O(1) |
insert(iterator pos, T value ) | Вставляет элемент(ы) в заданную позицию. | v.insert(v.begin() + 2, 10); v.insert(v.begin() + 2, {3, 4, 5}); v.insert(v.begin(), v.end() - 3, v.end()); | O(n) |
max_size() | Возвращает максимально возможный размер вектора. | size_t msize = v.max_size(); | O(1) |
pop_back() | Удаляет последний элемент вектора вектора. | v.pop_back(); | O(1) |
push_back(const T& value) | Вставляет элемент со значением value в конец вектора. | v.push_back(10); | O(1) |
rbegin() | Возвращает реверсивный итератор на конец вектора. | auto i = v.rbegin(); | O(1) |
rend() | Возвращает реверсивный итератор на начало вектора. | auto i = v.rend(); | O(1) |
reserve(size_t n) | Резервирует в векторе память под добавление n элементов. | v.reserve(1000); | O(n) |
resize(size_t new_size) | Изменяет количество элементов вектора до new_size | v.resize(1000); | O(n) |
size() | Возвращает размер вектора. | size_t size = v.size(); | O(1) |
swap(vector& v2) | Обменивает содержимое векторов | v.swap(v2); | O(1) |
vector | Конструктор без аргументов. Создает новый пустой вектор. | vector<int> v; | O(1) |
vector(int size) | Конструктор. Создает вектор с заданным количеством элементов | vector<int> v(10); | O(n) |
vector(int size, int value) | Конструктор. Создает вектор с количеством элементов size и значением value | vector<int> v(10, 3); | O(n) |
vector(const vector v) | Конструктор копирования. Создает вектор со значениями вектора v | vector<int> v1(v); vector v1(v); | O(n) |
vector(iterator it_start, iterator it_stop) | Конструктор. Создает вектор из диапазона итераторов другого контейнера. | vector v2(v.begin(), v.end()); | O(n) |
vector <int> ar; // Создание вектора
ar.resize(10); // Изменение длины вектора до 10 элементов
vector <int> ar(10); // Создание вектора в 10 элементов
vector <int> ar(10, 3); // Создание вектора в 10 элементов инициализированных значением 3
vector<vector<int>> ar(10, vector<int>(20)); // 2D вектор векторов размером 10х20 элементов
vector<vector<vector<int>>> ar(10, vector<vector<int>>(20, vector<int>(30))); // 3D вектор размером 10х20х30
vector<int> ar = { 10, 8, 6, 4, 2, 1 }; // Создание вектора с инициализацией
vector<int> ar{ 10, 8, 6, 4, 2, 1 }; // Создание вектора с uniform инициализацией
ar.insert(ar.begin() + 1 , 25); // Вставить в первый индекс значение 25
for (const int x : ar) // Перебираем все значения вектора ar
std::cout << x << " "; //10 25 8 6 4 2 1
ar.insert(ar.end(), 11); // Вставить после последнего элемента значение 11
//10 25 8 6 4 2 1 11
ar.erase(ar.end() - 2, ar.end()-1); // Удалить предпоследний элемент вектора (от ar.end() - 2 до ar.end() - 1)
//10 25 8 6 4 2 11
#include <iostream> // cout
#include <vector> // vector
using namespace std;
int main(){
vector <int> ar; // Объявление вектора
ar.resize(2); // Задание вектору размера
ar[0] = 10; // Инициализация элемента
ar[1] = 15; // Инициализация элемента
cout << ar[0] << ' ' << ar[1] << endl; // 10 15
}
std::vector<std::vector<int>> inputSample{
{0, 0},
{0, 1},
{1, 0},
{1, 1},
};
#include <iostream> // cout
#include <vector> // vector
using namespace std;
int main(){
int x_size = 3;
int y_size = 4;
vector<vector<int>> ar(x_size, vector<int>(y_size)); // Двухмерный массив размером [x_size, y_size]
for(uint64_t x = 0; x < ar.size(); x++){ // Перебор x
for(uint64_t y = 0; y < ar[x].size(); y++){ // Перебор y
ar[x][y] = x * y; // Присваиваем значения элементам массива
cout << "ar[" << x << "][" << y << "] = " << ar[x][y] << "\t"; // Выводим значения элементов вектора
}
cout << '\n';
}
}
/* Вывод программы в консоль
ar[0][0] = 0 ar[0][1] = 0 ar[0][2] = 0 ar[0][3] = 0
ar[1][0] = 0 ar[1][1] = 1 ar[1][2] = 2 ar[1][3] = 3
ar[2][0] = 0 ar[2][1] = 2 ar[2][2] = 4 ar[2][3] = 6
*/
#include <iostream> // cout
#include <vector> // vector
using namespace std;
int main(){
vector<vector<int>> weight; // Двумерный массив
weight.resize(4); // 4 строки
for(unsigned long long i = 0; i < weight.size(); i++){ // Перебор строк вектора
weight[i].resize(6); // создаем 6 элементов в строке i
for(unsigned long long n = 0; n < weight[i].size(); n++){ // Перебор элементов n строки i вектора
weight[i][n] = (i + 1) * 10 + n + 1; // Присваиваем значения элементам строка_столбец
cout << weight[i][n] << "\t"; // Выводим значения элементов вектора
}
cout << '\n';
}
}
/* Вывод программы в консоль
11 12 13 14 15 16
21 22 23 24 25 26
31 32 33 34 35 36
41 42 43 44 45 46
*/
#include <iostream> // cout
#include <vector> // vector
using namespace std;
int main(){
vector<vector<vector<int>>> cord; // Трехмерный массив
cord.push_back({{111, 222, 333}}); // Вносим значение
cord.push_back({{444, 555, 666}}); // Вносим значение
cord.push_back({{777, 888, 999}}); // Вносим значение
cord.push_back({{112, 113, 114}}); // Вносим значение
for(uint64_t x = 0; x < cord.size(); x++){ // Перебор x
for(uint64_t y = 0; y < cord[x].size(); y++){ // Перебор y
for(uint64_t z = 0; z < cord[x][y].size(); z++){ // Перебор z
cout << cord[x][y][z] << "\t"; // Выводим значения элементов вектора
}
}
cout << '\n';
}
}
/* Вывод программы в консоль
111 222 333
444 555 666
777 888 999
112 113 114
*/
По аналогии можно создавать вектора любой размерности.
#include <iostream> // cout
#include <vector> // vector
void print_v(const std::vector<int> ar); // Объявление функции принимающей вектор
void print_v(const std::vector<int> ar){ // Определение функции принимающей вектор
for(int x : ar){ // Перебираем элементы вектора
std::cout << x << " "; // Выводим элементы вектора
}
}
int main(){
print_v({2, 3, 4}); // Вызов функции с явным заданием вектора
std::vector<int> v{30, 20, 10}; // Создаем вектор v
print_v(v); // Вызов функции с вектором v
}
/* Вывод программы
2 3 4 30 20 10
*/
#include <iostream> // cout
#include <vector> // vector
std::vector<int> point_v(int x, int y); // Объявление функции возвращающей вектор
void print_v(std::vector<int> ar); // Объявление функции принимающей вектор
std::vector<int> point_v(int x, int y){ // Определение функции возвращающей вектор
static std::vector<int> pt{x, y}; // Создаем вектор точки из двух координат
print_v(pt); //3 5 0x81913ff570 Выводим значения вектора
return pt; // Возвращаем вектор
}
void print_v(std::vector<int> ar){ // Определение функции принимающей вектор
for(const int x : ar){ // Перебираем элементы вектора
std::cout << x << " "; // Выводим элементы вектора
}
std::cout << &ar << std::endl; // Выводим адрес вектора
}
int main(){
std::vector<int> v = point_v(3, 5); // Возвращаем вектор
print_v(v); //3 5 0x81913ff600 Выводим значение вектора
}
/* Вывод программы
3 5 0xf6abdff930
3 5 0xf6abdff9c0
*/
#include <iostream> // cout
#include <vector> // vector
void print_v(std::vector<int> ar); // Объявление функции принимающей вектор
void print_v(std::vector<int> ar){ // Определение функции принимающей вектор
for(uint64_t i = 0; i < ar.size(); i++){ // Перебираем элементы вектора
std::cout << ar[i] << " "; // Выводим элементы вектора
ar[i] = 0; // Обнуляем значения вектора (этого не произойдет, вектор передается в функцию по значению - копируется)
}
}
int main(){
print_v({2, 3, 4}); // Вызов функции с явным заданием вектора
std::vector<int> v{30, 20, 10}; // Создаем вектор v
print_v(v); // Вызов функции с вектором v
print_v(v); // Видим что предыдущая функция не изменила значения вектора
}
/* Вывод программы
2 3 4 30 20 10 30 20 10
*/
#include <iostream> // cout
#include <vector> // vector
void print_v(std::vector<int> &ar); // Объявление функции принимающей вектор
void print_v(std::vector<int> &ar){ // Определение функции принимающей вектор
for(uint64_t i = 0; i < ar.size(); i++){ // Перебираем элементы вектора
std::cout << ar[i] << " "; // Выводим элементы вектора
ar[i] = 0; // Обнуляем значения вектора (этого не произойдет, вектор передается в функцию по значению - копируется)
}
}
int main(){
//print_v({2, 3, 4}); // Вызов функции с явным заданием вектора вызывает ошибку
std::vector<int> v{30, 20, 10}; // Создаем вектор v
print_v(v); // Вызов функции с вектором v
print_v(v); // Видим что предыдущая функция не изменила значения вектора
}
/* Вывод программы
30 20 10 0 0 0
*/
#include <iostream> //cout
#include <vector> // vector
#include <algorithm> // sort()
using namespace std;
int main() {
vector<int> data = {3, 1, 4, 1, 5, 9, 2, 6};
sort(data.begin(), data.end()); // Сортировка вектора по возрастанию
for(int n : data){
cout << n << ' '; //1 1 2 3 4 5 6 9
}
cout << endl;
sort(data.rbegin(), data.rend()); // Сортировка вектора по убыванию
//sort(data.begin(), data.end(), greater<int>()); // Аналогично Сортировка вектора по убыванию
for(int n : data){
cout << n << ' '; //9 6 5 4 3 2 1 1
}
cout << endl;
}
Для сортировки контейнеров с типами данных для которых не определен оператор <
потребуется реализовать этот функционал
#include <iostream> //cout
#include <vector> // vector
#include <algorithm> // sort()
using namespace std;
struct Point{
int x;
int y;
int r;
};
int main() {
vector<Point> points{{2, 0, 2}, {2, 3, 4}, {0, 1, 1}, {3, 4, 5}} ; // Завели вектор структур
sort(points.begin(), points.end(), [](const Point &x, const Point &y){ // Сортируем вектор с лямбдой
return x.r < y.r; // Определяем критерий сортировки
});
for(size_t i = 0; i < points.size(); i++){ // Выводим вектор
cout << points[i].x << " " << points[i].y << endl;
}
}
/* Вывод программы
0 1
2 0
2 3
3 4
*/
1) Поиск в векторе осуществляется с помощью функции find определенной в #include <algorithm>.
2) В ряде случаев поиск в [unordered] map(set) оказывается быстрее.
#include <iostream> // cout
#include <vector> // vector
#include <algorithm>// find
using namespace std;
int main(){
vector<int> v{2, 3, 5, 7, 11, 13, 17, 19}; // Создаем вектор простых чисел
vector<int> find_ar{1, 2, 3, 4, 5, 6};
for(auto find_val : find_ar){ // Перебираем значения которые ищем
auto it = find(v.begin(), v.end(), find_val); // Находим итератор на find_val в векторе v, или v.end() если не найдено
if( it == v.end() ){ // Значение не найдено
cout << "value " << find_val << " not find" << endl;
}else{ // Значение найдено
int index = distance(begin(v), it); // Находим индекс найденного значения в векторе v
cout << "value " << find_val << " find in vector v in index " << index << endl;
}
}
}
/* Вывод программы
value 1 not find
value 2 find in vector v in index 0
value 3 find in vector v in index 1
value 4 not find
value 5 find in vector v in index 2
value 6 not find
*/
reference operator[](size_t index); // constexpr начиная с C++20
const_reference operator[](size_t index) const; // constexpr начиная с C++20
1) Индекс в операторе [] имеет тип std::size_t (unsigned long long).
2) Оператор [] возвращает ссылку соответствующую индексу ячейку вектора и позволяет как считать оттуда значения так и записывать.
3) Доступ по индексу имеет константную сложность О(1) - время доступа не зависит от размера вектора и номера индекса.
#include <iostream> // cout
#include <vector> // vector
int main(){
std::vector <int> ar = {0, 1, 2, 4}; // ar = [0, 1, 2, 4] Объявление вектора
ar[0] = 5; // ar = [5, 1, 2, 4]
ar[1] = ar[3]; // ar = [5, 4, 2, 4]
std::cout << ar[1]; //4
}
void assign(size_t index, const T& value); // (новый размер вектора, значения элементов вектора)
void assign(InputIt first, InputIt last); // (итератор начала, итератор конца) Меняет размер и значения вектора из диапазона итераторов
void assign(std::initializer_list<T> ilist); // (списковая инициализация) Меняет размер и значения вектора из списка
1) Функция assign ничего не возвращает (имеет тип void).
2) Функция assign меняет размер и значения вектора который ее вызывает.
3) Функция assign имеет линейную сложность О(n) - время работы функции пропорционально новому размеру вектора.
#include <iostream> // cout
#include <vector> // vector
#include <list> // list
void print_vector(std::vector<int> &vec){
for(auto i : vec){
std::cout << i << " "; // Выводим значения вектора
}
std::cout << &vec << std::endl; // Выводим адрес вектора
}
int main(){
std::vector <int> ar(3, 1); // Создаем вектор из трех элементов со значениями 1
print_vector(ar); // 1 1 1 0x63fde0 Выводим значения вектора и его адрес
ar.assign(4, 10); // Меняет размер вектора до 4х элементов со значениями 10
print_vector(ar); // 10 10 10 10 0x63fde0 Выводим значения вектора и его адрес
std::list<int> ls{0, 1, 2, 3, 4, 5, 6, 7}; // Создаем список
ar.assign(ls.begin(), ls.end()); // Меняем значения вектора из диапазона итераторов другого контейнера
print_vector(ar); //0 1 2 3 4 5 6 7 0x63fde0 Выводим значения вектора и его адрес
ar.assign({1, 3, 5, 7}); // Меняем значения вектора из значений списка
print_vector(ar); //1, 3, 5, 7 0x63fde0 Выводим значения вектора и его адрес
}
reference at(size_t index); // constexpr начиная с C++20
const_reference at(size_t index) const; // constexpr начиная с C++20
1) Функция at возвращает ссылку на элемент вектора индекс которого передан ей в качестве аргумента.
2) Функция at подобна оператору [], но выбрасывает исключение std::out_of_range при выходе за границы.
3) Функция assign имеет константную сложность О(1) - время работы функции не зависит от размера вектора и номера индекса.
#include <iostream> // cout
#include <vector> // vector
int main(){
std::vector <int> ar = {0, 1, 2, 4}; // ar = [0, 1, 2, 4] Объявление вектора
ar.at(0) = 5; // ar = [5, 1, 2, 4]
ar.at(1) = ar.at(3); // ar = [5, 4, 2, 4]
std::cout << ar.at(1) << std::endl; //4
try {
ar.at(5) = 7; // Выход за пределы диапазона (индекс 5 не существует). Будет напечатано exception (5)
} catch (...) { // Ловим все исключения
std::cout << "exception (5)" << std::endl;
}
try {
ar.at(-1) = 7; // Выход за пределы диапазона (индекс -1 не существует). Будет напечатано exception (-1)
} catch (std::out_of_range) { // Ловим исключение std::out_of_range
std::cout << "exception (-1)" << std::endl;
}
std::cout << "end";
}
/* Вывод программы:
4
exception (5)
exception (-1)
end
*/
reference back(); // constexpr начиная с C++20
const_reference back() const; // constexpr начиная с C++20
1) Функция back() возвращает ссылку на последний элемент вектора.
2) Функция back() примененная к пустому контейнеру (с нулевым размером), приводит к неопределенному поведению.
3) Функция back()имеет константную сложность О(1) - время работы функции не зависит от размера вектора.
#include <iostream> // cout
#include <vector> // vector
int main(){
std::vector<int> v{0, 1, 2, 3}; // Создаем вектор
std::cout << v.back() << std::endl; //3 Выводим значение последнего элемента вектора
v.back() = 10; // Присваиваем последнему элементу вектора значение 10
std::cout << v.back(); //10 Выводим значение последнего элемента вектора
}
/* Вывод программы:
3
10
*/
iterator begin(); // noexcept начиная с C++11, constexpr начиная с C++20
const_iterator begin() const; // noexcept начиная с C++11, constexpr начиная с C++20
const_iterator cbegin() const noexcept; // с C++11, constexpr начиная с C++20
1) Функция begin() возвращает итератор на первый элемент вектора.
2) Функция cbegin() возвращает константный итератор на первый элемент вектора. Значение первого элемента нельзя изменить через итератор cbegin();
3) Функция begin() или сbegin() примененная к пустому контейнеру (с нулевым размером), возвращает итератор end().
4) Выражение v.front() эквивалентно *v.begin().
5) Функция begin() или сbegin() имеет константную сложность О(1) - время работы функции не зависит от размера вектора.
#include <iostream> // cout
#include <vector> // vector
int main(){
std::vector<int> v{4, 6, 8}; // Создаем вектор
std::cout << *v.begin() << std::endl; //4 Выводим значение первого элемента вектора
*v.begin() = 10; // Присваиваем первому элементу вектора значение 10
std::cout << *v.begin() << std::endl; //10 Выводим значение первого элемента вектора
std::cout << *v.cbegin() << std::endl; //10 Выводим значение первого элемента вектора через cbegin()
// *v.cbegin() = 10; // Ошибка! Нельзя изменить значение элемента через cbegin()
}
/* Вывод программы:
4
10
10
*/
size_type capacity() const; // C++98
size_type capacity() const noexcept; // C++11
Изменение размера вектора это затратная операция. Для того, чтобы не делать изменение размера вектора при добавлении одного элемента, вектор при изменении размера резервирует размер для большего количества элементов.
1) Функция capacity() возвращает количество элементов вектора которые могут быть в векторе до изменения его зарезервированного размера.
2) При изменении зарезервированного размера вектора, он увеличивается в два раза.
3) Зарезервированный размер вектора может только увеличиваться, но не уменьшаться.
4) Функция capacity() имеет константную сложность О(1) - время работы функции не зависит от размера вектора.
#include <iostream> // cout
#include <vector> // vector
int main(){
std::vector<int> v; // Создаем вектор
for(int i = 0; i < 10; i++){
std::cout << "size = " << v.size() << ", capacity = " << v.capacity() << std::endl; // Выводим размер и емкость вектора
v.push_back(i); // Добавляем элемент в конец вектора
}
for(int i = 0; i < 10; i++){
v.pop_back(); // Удаляем элемент из конца вектора
std::cout << "size = " << v.size() << ", capacity = " << v.capacity() << std::endl; // Выводим размер и емкость вектора
}
}
/* Вывод программы:
size = 0, capacity = 0
size = 1, capacity = 1
size = 2, capacity = 2
size = 3, capacity = 4
size = 4, capacity = 4
size = 5, capacity = 8
size = 6, capacity = 8
size = 7, capacity = 8
size = 8, capacity = 8
size = 9, capacity = 16
size = 9, capacity = 16
size = 8, capacity = 16
size = 7, capacity = 16
size = 6, capacity = 16
size = 5, capacity = 16
size = 4, capacity = 16
size = 3, capacity = 16
size = 2, capacity = 16
size = 1, capacity = 16
size = 0, capacity = 16
*/
void clear(); // noexcept c C++11, constexpr c C++20
1) Функция clear() удаляет все элементы вектора.
2) После вызова функции clear() размер вектора, возвращаемый функцией size(), становится нулевым.
3) После вызова функции clear(), зарезервированный размер вектора, возвращаемый функцией capacity(), не меняется.
4) Функция clear() имеет линейную сложность О(n) - время работы функции прямо пропорционально размеру вектора.
#include <iostream> // cout
#include <vector> // vector
int main(){
std::vector<int> v{2, 3, 4}; // Создаем вектор
std::cout << "size = " << v.size() << ", capacity = " << v.capacity() << std::endl; // Выводим размер и емкость вектора
v.clear(); // Очищаем вектор
std::cout << "size = " << v.size() << ", capacity = " << v.capacity() << std::endl; // Выводим размер и емкость вектора
}
/* Вывод программы:
size = 3, capacity = 3
size = 0, capacity = 3
*/
T* data(); // noexcept c C++11, constexpr c C++20
const T* data() const; // noexcept c C++11, constexpr c C++20
1) Функция data() возвращает указатель на массив данных, но не на контейнер.
2) Указатель возвращаемый функцией data() указывает на начало массива содержащего size()элементов.
3) Если размер вектора нулевой, то указатель возвращаемый функцией data(), может быть нулевой, а может и не быть нулевым - в этом случае указатель нельзя разыменовывать (получать значение лежащее по адресу указателя).
4) Функция data() имеет константную сложность О(1) - время работы функции не зависит от размера вектора.
#include <iostream> // cout
#include <vector> // vector
int main(){
std::vector<int> v{2, 3, 4}; // Создаем вектор
std::cout << "&v = \t\t " << &v << std::endl; // Выводим адрес вектора
int* p = v.data(); // Получаем указатель на данные вектора (на массив int)
for(unsigned int i = 0; i < v.size(); i++){ // Перебираем элементы массива
std::cout << "p[" << i << "] = " << p[i] << ", p + " << i << " = " << p + i << std::endl; // Выводим значения и адрес массива данных содержащихся в векторе
}
}
/* Вывод программы:
&v = 0x60fdc0
p[0] = 2, p + 0 = 0xf41960
p[1] = 3, p + 1 = 0xf41964
p[2] = 4, p + 2 = 0xf41968
*/
iterator emplace(iterator it, T value);
1) Функция emplace() возвращает итератор на вставленный элемент.
2) Итератор it, передаваемый как аргумент, указывает на элемент перед которым вставляется элемент T (второй аргумент). Если итератор равен end(), то элемент вставляется в конец вектора (становится последним элементом).
3) Функция emplace() имеет линейную сложность О(n) - время работы функции пропорционально расстоянию от it до конца вектора.
#include <iostream>
#include <vector>
int main(){
std::vector<int> v{3, 5, 7}; // Создаем вектор из трех целых чисел 3, 5 и 7
auto it = v.emplace(v.begin(), 1); //1 3 5 7 Вставляем перед первым элементом значение 1.
std::cout << *it << "\n"; //1 Выводим значение вставленного элемента через итератор
it = v.emplace(v.end(), 9); //1 3 5 7 9 Вставляем перед последним элементом значение 9, т.к end() указывает на место ПОСЛЕ последнего элемента.
std::cout << *it << "\n"; //9 Выводим значение вставленного элемента через итератор
it = v.emplace(it, 8); //1 3 5 7 8 9 Вставляем перед последним элементом значение 8.
std::cout << *it << "\n"; //8 Выводим значение вставленного элемента через итератор
it = v.emplace(v.begin() + 2, 4); //1 3 4 5 7 8 9 Вставляем перед (первым элементом плюс два элемента) значение 4.
std::cout << *it << "\n"; //4 Выводим значение вставленного элемента через итератор
for(auto i : v){ // Перебираем значения элементов
std::cout << i << " "; //1 3 4 5 7 8 9
}
}
void emplace_back(T value);
1) Функция emplace_back(value) аналогична emplace(v.end(), value) (только возвращает void а не итератор).
2) Функция emplace_back() имеет константную сложность О(1) - время работы функции не зависит от размера вектора.
#include <iostream>
#include <vector>
int main(){
std::vector<int> v{3, 5, 7}; // Создаем вектор из трех целых чисел 3, 5 и 7
v.emplace_back(9); //3 5 7 9 Вставляем после последнего элемента значение 9.
v.emplace_back(11); //3 5 7 9 11 Вставляем после последнего элемента значение 9.
for(auto i : v){ // Перебираем значения элементов
std::cout << i << " "; //3 5 7 9 11
}
}
bool empty(); // noexcept c C11++, constexpr c C20++
1) Функция empty() возвращает true, если вектор пустой и возвращает false в противном случае
2) В качестве аналога функции empty() может выступать выражение !size(), где функция size() возвращает размер вектора в элементах.
3) Функция empty() имеет константную сложность О(1) - время работы функции не зависит от размера вектора.
#include <iostream>
#include <vector>
int main(){
std::vector<int> v; // Создаем пустой вектор
std::cout << (v.empty() ? "EMPTY" : "NOT EMPTY") << "\n"; //EMPTY
v.push_back(10); // Помещаем в конец вектора значение 10. Теперь вектор не пустой.
std::cout << (v.empty() ? "EMPTY" : "NOT EMPTY"); //NOT EMPTY
}
bool vector_empty(); // noexcept c C11++, constexpr c C20++
1) Функция empty() возвращает true, если вектор пустой и возвращает false в противном случае
2) В качестве аналога функции empty() может выступать выражение !size(), где функция size() возвращает размер вектора в элементах.
3) Функция empty() имеет константную сложность О(1) - время работы функции не зависит от размера вектора.
#include <iostream>
#include <vector>
int main(){
std::vector<int> v; // Создаем пустой вектор
std::cout << (v.empty() ? "EMPTY" : "NOT EMPTY") << "\n"; //EMPTY
v.push_back(10); // Помещаем в конец вектора значение 10. Теперь вектор не пустой.
std::cout << (v.empty() ? "EMPTY" : "NOT EMPTY"); //NOT EMPTY
}
iterator end(); // noexcept c C11++, constexpr c C20++
const_iterator cend(); // noexcept c C11++, constexpr c C20++
1) Функция end() возвращает итератор на элемент после последнего.
2) Функция сend() возвращает константный итератор на элемент после последнего, у которого нельзя изменить значение элемента через разыменование итератора (оператором *).
3) Для пустого вектора (без значений), итератор возвращаемый функцией end() или cend() равен итератору возвращаемому функцией begin() или cbegin().
4) Итератор возвращаемый функцией end() или cend() не указывает на реальный элемент вектора, поэтому его нельзя разыменовывать (оператором *).
5) Функция end() или cend() имеет константную сложность О(1) - время работы функции не зависит от размера вектора.
#include <iostream>
#include <vector>
int main(){
std::vector<int> v{1, 2}; // Создаем вектор
std::cout << *(v.end() - 1) << std::endl; //2 Выводим значение последнего элемента (перед end())
auto it = v.end(); // Присваиваем итератору it значение end()
std::cout << *(it - 2) << std::endl; //1 Выводим значение предпоследнего элемента
*(--v.end()) = 10; // Изменили значение у последнего элемента
// *(--v.cend()) = 10; // Ошибка нельзя изменять значение у константного итератора (cend())
// *(v.cend() - 1) = 10; // Так тоже нельзя изменять значение у константного итератора (cend())
for(auto i = v.begin(); i != v.end(); i++){ // Перебираем значения через итераторы
std::cout << *i << " "; //1 10 Выводим значения вектора через итераторы
}
v.clear();
if(v.begin() == v.end()){
std::cout << "\nv.begin() == v.end() if vector is empty"; //v.begin() == v.end() if vector is empty
}
}
iterator erase(iterator pos); // Удаляет элемент из позиции указываемой итератором pos
iterator erase(iterator first, iterator last); // Удаляет элементs из позиций от first включительно, до last не включительно
1) Функция erase() возвращает итератор на элемент после последнего удаленного (или end()).
2) Функция erase() имеет линейную сложность О(n) - время работы функции линейно зависит от размера удаляемых элементов и от количества элементов от pos (last) до конца (end()) вектора.
#include <iostream>
#include <vector>
int main(){
std::vector<int> v{1, 2, 3, 4, 5, 6}; // Создаем вектор
auto it = v.erase(v.begin() + 2, v.end() - 2); // {1, 2, 5, 6} Удаляем диапазон элементов {3, 4} - от v.begin() + 2 включительно, до (v.end() - 2) не включительно.
if(it == v.end()){
std::cout << "it == v.end()\n"; // Эта ветка не стработает
}else{
std::cout << *it << std::endl; //5
}
it = v.erase(it); // {1, 2, 6} Удаляет элемент на который указывает итератор {5}
if(it == v.end()){
std::cout << "it == v.end()\n"; // Эта ветка не стработает
}else{
std::cout << *it << std::endl; //6 Итератор it указывает на последний элемент вектора
}
// v.erase(v.end()); // Ошибка! v.end() не указывает на действительный элемент вектора
it = v.erase(v.end() - 1); // {1, 2} Удаляется последний элемент вектора {6}
if(it == v.end()){
std::cout << "it == v.end()\n"; //it == v.end() Сработает эта ветка
}else{
std::cout << *it << std::endl; // Эта ветка не стработает
}
for(auto i : v){ // Перебираем элементы вектора
std::cout << i << " "; //1 2
}
}
/* Вывод программы
5
6
it == v.end()
1 2
*/
reference front();
1) Функция front() возвращает ссылку на первый элемент вектора.
2) Функция front() нельзя применять к пустому вектору, это вызовет неопределенное поведение.
3) Выражение v.front() эквивалентно *v.begin().
4) Функция front() имеет константную сложность О(1) - время работы функции не зависит от размера вектора.
#include <iostream>
#include <vector>
int main(){
std::vector<int> v{1, 2, 3, 4}; // Создаем вектор
std::cout << v.front() << std::endl; //1
v.front() = 3; // Присваиваем первому элементу значение 3
std::cout << v.front() << std::endl; //3
for(auto i : v){ // Перебираем элементы вектора
std::cout << i << " "; //3 2 3 4
}
}
/* Вывод программы
1
3
3 2 3 4
*/
iterator insert( const_iterator pos, const T& value ); // Вставляет значение value перед итератором pos
iterator insert( const_iterator pos, size_type count, const T& value ); // Вставляет значение value в количестве count штук перед итератором pos
iterator insert( const_iterator pos, iterator first, iterator last ); // Вставляет значения от итератора first включительно, до итератора last не включительно перед итератором pos
iterator insert( const_iterator pos, std::initializer_list<T> ilist ); // Вставляет значения из списка инициализации ilist перед итератором pos
1) Функция insert() вставляет элемент(ы) перед итератором pos (первым аргументом).
2) Вставлять значения итераторами из вектора в который и вставляют нельзя, это вызовет неопределенное поведение.
3) Итератор pos может быть как begin, тогда элемент(ы) будут вставлены в начало вектора, так и end, тогда элемент(ы) будут вставлены в конец вектора.
4) Функция insert() имеет линейную сложность О(n) - время работы функции линейно зависит от размера вставляемых элементов и от расстояния от места вставки до конца вектора.
#include <iostream>
#include <vector>
using namespace std;
int main(){
vector<int> v{1, 2, 3, 4}; // Создаем вектор
vector<int> v2{20, 30, 40, 50}; // Создаем вектор
auto it = v.insert(v.begin(), 10); // {10, 1, 2, 3, 4} Вставляем значение 10 перед первым элементом
cout << *it <<endl; //10 Итератор указывает на вставленный элемент
it = v.insert(v.begin() + 1, 3, 5); // {10, 5, 5, 5, 1, 2, 3, 4} Вставляем три элемента со значением 5 перед вторым элементом
cout << *it <<endl; //5 Итератор указывает на первый вставленный элемент
it = v.insert(v.end(), v2.begin() + 1, v2.end() - 1); // {10, 5, 5, 5, 1, 2, 3, 4, 30. 40} Вставляем значения {30, 40} из другого контейнера итераторами в конец вектора
cout << *it <<endl; //30 Итератор указывает на первый вставленный элемент
it = v.insert(v.end() - 2, {60, 70}); // {10, 5, 5, 5, 1, 2, 3, 4, 60, 70, 30, 40} Вставляем значения {60, 70} с помощью списковой инициализации перед вторым элементом от конца вектора
cout << *it <<endl; //60 Итератор указывает на первый вставленный элемент
for(auto i : v){ // Перебираем элементы вектора
cout << i << " "; //10 5 5 5 1 2 3 4 60 70 30 40
}
}
/* Вывод программы
10
5
30
60
10 5 5 5 1 2 3 4 60 70 30 40
*/
size_type max_size() const; // noexcept c C++11, constexpr c C++20
1) Функция max_size() возвращает максимально возможный размер вектора. Это значение показывает теоретический максимальный размера контейнера, являющийся не более std::numeric_limits
2) Во время выполнения программы размер контейнера может быть ограничен значением, меньшим, чем max_size(), исходя из объема доступной оперативной памяти.
3) Функция max_size() имеет константную сложность О(1) - время работы функции не зависит от текущего размера вектора.
#include <iostream>
#include <vector>
using namespace std;
int main(){
vector<int> v{1, 2, 3, 4}; // Создаем вектор
cout << v.max_size() << "\tmax_size()" << endl;
cout << std::numeric_limits<size_t>::max() << "\tstd::numeric_limits<size_t>::max()";
}
/* Вывод программы
4611686018427387903 max_size()
18446744073709551615 std::numeric_limits<size_t>::max()
*/
void pop_back(); // constexpr c C++20
1) Функция pop_back() удаляет последний элемент контейнера.
2) Функция pop_back() имеет константную сложность О(1) - время работы функции не зависит от размера вектора.
#include <iostream>
#include <vector>
using namespace std;
int main(){
vector<int> v{1, 2, 3, 4}; // Создаем вектор
cout << v.back() << endl; //4 Выводим значение последнего элемента контейнера
v.pop_back(); // Удаляем последний элемент контейнера {4}
cout << v.back() << endl; //3 Выводим значение последнего элемента контейнера
v.pop_back(); // Удаляем последний элемент контейнера {3}
cout << v.back() << endl; //2 Выводим значение последнего элемента контейнера
for(auto i : v){ // Перебираем элементы вектора
cout << i << " "; //1 2 Выводим значения вектора
}
}
/* Вывод программы
4
3
2
1 2
*/
void push_back( const T& value ); // constexpr с C++20 Копирует value в конец вектора
void push_back( T&& value ); // с C++11, constexpr C++20 Перемещает value в конец вектора
1) Функция push_back() вставляет элемент value в конец вектора.
2) Функция push_back() имеет константную сложность О(1) - время работы функции не зависит от размера вектора.
#include <iostream>
#include <vector>
using namespace std;
int main(){
vector<int> v{1, 2, 3}; // Создаем вектор
v.push_back(4);
for(auto i : v){ // Перебираем элементы вектора
cout << i << " "; //1 2 3 4 Выводим значения вектора
}
}
reverse_iterator rbegin(); // Возвращает реверсивный итератор на последний элемент вектора
reverse_iterator crbegin(); // Возвращает константный реверсивный итератор на последний элемент вектора. Нельзя изменить значение по адресу итератора
reverse_iterator rend(); // Возвращает реверсивный итератор на место перед первым элементом вектора.
reverse_iterator crend(); // Возвращает реверсивный итератор на место перед первым элементом вектора. Нельзя изменить значение по адресу итератора.
1) Функции rbegin() rend() используют обычно для перебора вектора в обратном направлении, достаточно добавить букву r перед begin() end() в цикле for. При этом в цикле for не требуется менять инкремент итератора (it++).
2) Функции rbegin() rend() возвращают константные итераторы, с помощью которых можно только считывать значение итератора но нельзя его изменить.
3) Разыменовывать и получать доступ к значению итератора возвращаемый функциями rend() crend() нельзя, так как он не указывает на действительный элемент вектора (указывает на место перед первым элементов вектора).
4) Функции rbegin() rend() crbegin() crend() имеет константную сложность О(1) - время работы функции не зависит от размера вектора.
#include <iostream>
#include <vector>
using namespace std;
int main(){
vector<int> v{1, 2, 3, 4}; // Создаем вектор
auto it = v.rbegin();
*it = 5; // Присваиваем последнему элементу вектора значение 5 (был 4)
for(auto it = v.begin(); it != v.end(); it++){ // Перебираем элементы вектора в прямом порядке
cout << *it << " "; //1 2 3 4 Выводим значения вектора
}
cout << " forward" << endl;
for(auto it = v.rbegin(); it != v.rend(); it++){ // Перебираем элементы вектора в реверсном порядке
cout << *it << " "; //1 2 3 4 Выводим значения вектора
}
cout << " reverse" << endl;
}
/* Вывод программы
1 2 3 5 forward
5 3 2 1 reverse
*/
void reserve(size_t new_capacity); // constexpr c C++20
1) Функции reserve(new_capacity) резервирует в векторе память под new_capacity элементов, при этом размер вектора (функция size() и значения его элементов не меняются.
2) Функции reserve() меняет значение возвращаемое функцией capacity().
3) Функции reserve() имеет линейную сложность О(n) - время работы функции линейно зависит от размера зарезервированных элементов вектора.
#include <iostream>
#include <vector>
using namespace std;
int main(){
vector<int> v{1, 2, 3, 4}; // Создаем вектор
cout << "size = " << v.size() << ", capacity = " << v.capacity() << endl;
v.reserve(10);
cout << "size = " << v.size() << ", capacity = " << v.capacity() << endl;
for(auto i : v){ // Перебираем элементы вектора
cout << i << " "; //1 2 3 4 Выводим значения вектора
}
}
/* Вывод программы
size = 4, capacity = 4
size = 4, capacity = 10
1 2 3 4
*/
void resize( size_t new_size ); // Изменяет размер вектора до new_size. constexpr с C++20
void resize( size_t new_size, const false_type& value ); // Изменяет размер вектора до new_size, со значением добавляемых элементов value. constexpr с C++20
1) Функции resize(new_size) изменяет количество элементов вектора (size()) до new_size.
2) Функции resize(new_size, value) изменяет количество элементов вектора (size()) до new_size со значением добавленных элементов value. Если размер вектора уменьшается, то уже имеющиеся элементы не меняют значения;
3) Функции resize() может менять количество элементов как в меньшую так и в большую сторону..
4) Емкость (capacity()) вектора, после вызова функции resize(), при увеличении элементов равна размеру (size()) вектора, а при уменьшении элементов - не изменяется.
5) Функции resize() имеет линейную сложность О(n) - время работы функции линейно зависит от текущего размера вектора и количества добавляемых элементов.
#include <iostream>
#include <vector>
using namespace std;
int main(){
vector<int> v{1, 2, 3}; // Создаем вектор
for(auto i : v){ // Перебираем элементы вектора
cout << i << " "; //1 2 3 Выводим значения вектора
}
cout << " size = " << v.size() << ", capacity = " << v.capacity() << endl; // Выводим размер и емкость вектора
v.resize(5); // Изменяем размер вектора с 3х до 5ти (добавляются элементы со значением 0)
for(auto i : v){ // Перебираем элементы вектора
cout << i << " "; //1 2 3 0 0 Выводим значения вектора
}
cout << " size = " << v.size() << ", capacity = " << v.capacity() << endl; // Выводим размер и емкость вектора
v.resize(10, 7); // Изменяем размер вектора с 5ти до 10ти (добавляются элементы со значением 7)
for(auto i : v){ // Перебираем элементы вектора
cout << i << " "; //1 2 3 0 0 7 7 7 7 7 Выводим значения вектора
}
cout << " size = " << v.size() << ", capacity = " << v.capacity() << endl; // Выводим размер и емкость вектора
v.resize(2); // Изменяем размер вектора с 10ти до 5ти (добавляются элементы со значением 0)
for(auto i : v){ // Перебираем элементы вектора
cout << i << " "; //1 2 Выводим значения вектора
}
cout << " size = " << v.size() << ", capacity = " << v.capacity() << endl; // Выводим размер и емкость вектора
}
/* Вывод программы
1 2 3 size = 3, capacity = 3
1 2 3 0 0 size = 5, capacity = 6
1 2 3 0 0 7 7 7 7 7 size = 10, capacity = 10
1 2 size = 2, capacity = 10
*/
size_t size(); // Возвращает размер вектора. noexcept c C++11. constexpr c C++20
1) Функции size() возвращает размер вектора (количество элементов вектора).
2) Функции size() имеет константную сложность О(1) - время работы функции не зависит от размера вектора.
#include <iostream>
#include <vector>
using namespace std;
int main(){
vector<int> v; // Создаем вектор
cout << "size = " << v.size() << endl;
v = {1, 3, 5};
cout << "size = " << v.size() << endl;
}
/* Вывод программы
size = 0
size = 3
*/
void swap( vector& other ); // Обменивает значения, размер и емкость двух векторов. noexcept c C++17, constexpr c C++20
1) Функции swap() обменивает значения, размер и емкость двух векторов.
2) Функция swap() не производит внутри копирование, перемещение или обмен значений элементов векторов.
3) Функция swap() не изменяет итераторов обмениваемых векторов, кроме end() - который становится недействительным.
4) Функции swap() имеет константную сложность О(1) - время работы функции не зависит от размеров векторов.
#include <iostream>
#include <vector>
using namespace std;
int main(){
vector<int> v1{1, 3, 5}; // Создаем вектор
cout << "v1 = "; // Выводим описание v1
for(auto i : v1){ // Перебираем элементы вектора v1
cout << i << " "; // Выводим значение элемента
}
cout << " size = " << v1.size() << ", capacity = " << v1.capacity() << endl; // Выводим размер и емкость вектора v1
vector<int> v2{2, 4, 6, 8, 10}; // Создаем вектор
cout << "v2 = "; // Выводим описание v2
for(auto i : v2){ // Перебираем элементы вектора v2
cout << i << " "; // Выводим значение элемента
}
cout << " size = " << v2.size() << ", capacity = " << v2.capacity() << endl; // Выводим размер и емкость вектора v1
v1.swap(v2); // Обмениваем значения векторов v1 и v2
cout << "swap v1 and v2" << endl << "v1 = "; // Выводим факт вызова функции swap() и описание v1
for(auto i : v1){ // Перебираем элементы вектора v1
cout << i << " "; // Выводим значение элемента
}
cout << " size = " << v1.size() << ", capacity = " << v1.capacity() << endl; // Выводим размер и емкость вектора v1
cout << "v2 = "; // Выводим описание v2
for(auto i : v2){ // Перебираем элементы вектора v2
cout << i << " "; // Выводим значение элемента
}
cout << " size = " << v2.size() << ", capacity = " << v2.capacity() << endl; // Выводим размер и емкость вектора v1
}
/* Вывод программы
v1 = 1 3 5 size = 3, capacity = 3
v2 = 2 4 6 8 10 size = 5, capacity = 5
swap v1 and v2
v1 = 2 4 6 8 10 size = 5, capacity = 5
v2 = 1 3 5 size = 3, capacity = 3
*/
vector(); // Конструктор по умолчанию. Создает пустой вектор (без элементов).
vector(size_t count); // Создает вектор c count элементами.
vector(size_t count, value_type value); // Создает вектор c count элементами инициализированные значением count.
vector(initializer_list<T> list); // Создает вектор со списковой инициализацией
vector(const vector& other); // Создает вектор с копией элементов другого вектора
vector(iterator it_first, iterator it_last); // Создает вектор из диапазона другого контейнера заданного итераторами
1) Функция vector() создает вектор и является конструктором класса vector.
2) Функции vector() имеет линейную сложность О(n) - время работы функции линейно зависит от размера создаваемого вектора.
#include <iostream>
#include <vector>
using namespace std;
int main(){
vector<int> v1; // Создаем вектор с конструктором по умолчанию и размером в 0 элементов
vector<int> v2(5); // Создаем вектор с 5ю элементами
vector<int> v3(5, 3); // Создаем вектор с 5ю элементами со значением 3
vector<int> v4{1, 3, 5}; // Создаем вектор со списковой инициализацией и тремя элементами
vector<int> v5({1, 3, 5}); // Создаем вектор со списковой инициализацией и тремя элементами (альтернативная запись)
vector<int> v6 = {1, 3, 5}; // Создаем вектор со списковой инициализацией и тремя элементами (альтернативная запись)
vector<int> v7(v6); // Создаем вектор с копией элементов другого вектора
vector<int> v8(v7.begin(), v7.end()); // Создаем вектор из диапазона другого контейнера заданного итераторами
}