Vector

Рассмотрим первый контейнер - альтернативу массиву - vector. Представленный в C++03, vector — это динамический массив, который может сам управлять выделенной для себе памятью. Это означает, что вы можете создавать массивы, длина которых задается во время выполнения. vector находится в заголовочном файле vector

#include <vector>
using namespace std;
 
// Нет необходимости указывать длину при инициализации
vector<int> array; 
vector<int> array2 = { 10, 8, 6, 4, 2, 1 }; // используется список инициализаторов для инициализации массива
vector<int> array3 { 10, 8, 6, 4, 2, 1 }; // используется uniform-инициализация для инициализации массива (начиная с C++11)

Подобно массивам доступ к элементам может выполняться как через оператор [] (который не выполняет проверку диапазона), так и через функцию at(). Отличие метода at от обращения при помощи квадратных скобок в том, что при использовании метода at происходит проверка правильности индекса, и в случае выхода за границы вектора происходит ошибка исполнения. Это полезно при отладке программ.

array[7] = 3; // без проверки диапазона 
array.at(8) = 4; // с проверкой диапазона

Также vector позволяет верунть “первый” и “последний” эдемент с помощью функций front и back

#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main()
{
	vector <int> g1; 
	for (int i = 1; i <= 10; i++)
		g1.push_back(i * 10);
	cout << "Reference operator [g] : g1[2] = " << g1[2];
	cout << endl;
	cout << "at : g1.at(4) = " << g1.at(4);
	cout << endl;
	cout << "front() : g1.front() = " << g1.front();
	cout << endl;
	cout << "back() : g1.back() = " << g1.back();
	cout << endl; 
	return 0;
}

Изменение размера вектора

Размер вектора можно узнать при помощи метода size(). Также есть метод empty(), возвращающий логическое значение (true, если вектор пустой).

Размер вектора можно изменить в любой момент, при помощи метода resize. У этого метода может быть один или два параметра. Вызов метода resize(n) изменяет размер вектора до n элементов (длина вектора может как уменьшится, так и увеличиться). Вызов метода resize(n, val) изменяет размер вектора до n элементов, и если при этом размер вектора увеличивается, то новые элементы получают значение, равное val.

Очень часто бывает полезно добавлять элементы в конец вектора по одному и удалять элементы из конца вектора по одному. Для добавления нового элемента, равного val, в конец вектора, используется метод push_back(val). Для удаления последнего элемента вектора используется метод pop_back() - он не возвращает значения.

#include <iostream>
#include <vector>
using namespace std;
int main() {
	vector<int> g;
	g.assign(5, 10); // 5 elements with value 10 each
	int sum = 0;
	g.push_back(10);
	g.push_back(20);
	g.push_back(30);
	while (!g.empty()) {
		sum += g.back();
	    g.pop_back();
	}
	cout << "The sum of the elements of g is : " << sum << '\n';
	return 0;
}

Добавление элемента в конец вектора осуществляется в среднем за O(1) (подробнее об O-нотации будет позже. Для нас счейчас можно отметить, что данная операция самая быстрая). Это реализовано за счет того, что память для хранения элементов вектора выделяется “с запасом”, то есть можно будет добавлять элементы по одному, пока не кончится запас памяти. Если запас памяти исчерпан, выделяется новая память, при этом “запас” размера вектора удваивается.

Очистить вектор можно при помощи метода clear(). Есить глобальная функиця swap, которая позволяем поменять местами содержимое двух векторов.

#include <iostream>
#include <vector>
using namespace std;
int main() {
	vector<int> g1;
	vector<int> g2;
	g1.push_back(10);
	g1.push_back(20);
	g2.push_back(30);
	g2.push_back(40);

	swap(g1, g2);
    
	g1.clear();
	g1.push_back(1000);
	cout << g1.front();
    return 0;
}

Вставка и удаление элементов в середину вектора

Метод erase позволяет удалять из середины вектора один или несколько элементов. Этот метод работает с итераторами. Подробнее

#include <iostream>
#include <vector>
using namespace std;
int main() {
	vector<int> g;
	for (int i = 1; i <= 10; i++)
		g.push_back(i * 2);	// erase the 5th element
	g.erase(g.begin() + 4);	// erase the first 5 elements:
	g.erase(g.begin(), g.begin() + 5);
    cout << "g contains :";
	for (int i = 0; i < g.size(); ++i)
		cout << g[i] << '\t';
    return 0;
}

Метод insert позволяет вставлять в середину вектора новый элемент, или несколько равных элементов, или другой вектор, или фрагмент другого вектора. Подробнее

#include <iostream>
#include <vector> 
using namespace std;
int main()
{
	vector <int> g(3, 10); // 10 10 10
	vector <int> :: iterator it;
	it = g.begin();
	it = g.insert(it, 20); // 20 10 10 10
	g.insert(it, 2, 30);  // 30 30 20 10 10 10
	int gq [] = {50, 60, 70}; 
	g.insert(g.begin(), gq, gq + 3); // 50 60 70 30...
	cout << "g contains : ";
	for (it = g.begin(); it < g.end(); it++)
		cout << *it << '\t';
	return 0;
}

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

Присваивание и сравнение векторов

Содержимое одного вектора можно целиком скопировать в другой вектор при помощи операции присваивания: A = B.

Также вектора можно сравнивать на равенство и неравенство (A == B, A != B), и сравнивать их содержимое в лексикографическом порядке (A < B, A <= B, A > B, A >= B).

Создание многомерных векторов

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

vector<vector<int>> a;

Тем самым, a[i] будет вектором целых чисел, а обращаться к j-му элементу вектора a[i] можно через a[i][j].

Чтобы создать двумерный вектор размером n×m можно внешний вектор объявить размером n, а затем в цикле изменить размер каждого вложенного вектора:

vector<vector<int>> a(n);

for (int i = 0; i < n; ++i)
    a[i].resize(m);

Но можно сделать это и в одну строку, если передать вторым параметром для конструктора вектора конструктор, который создает вектор целых чисел длины m:

vector<vector<int>> a(n, vector<int>(m));

Размеры вложенных векторов могут изменяться и быть различными.