Поиск по сайту:

2D-векторы в C++ — Практическое руководство 2D-векторы


Также называемые векторами векторов, 2D-векторы в C++ формируют основу для динамического создания матриц, таблиц или любых других структур. Прежде чем перейти к теме двумерных векторов в C++, рекомендуется пройти руководство по использованию одномерных векторов в C++.

Включение заголовочного файла Vector

Мы не могли бы использовать векторы в C++, если бы не заголовочные файлы, включенные в начале программы. Чтобы использовать 2D-векторы, мы включаем:

#include<vector>

Вместо того, чтобы включать множество видов стандартных библиотек шаблонов (STL) один за другим, мы можем включить их все следующим образом:

#include<bits/stdc++.h>

Инициализация 2D-векторов в C++

Во-первых, мы изучим некоторые способы инициализации двумерного вектора. Следующий фрагмент кода объясняет инициализацию двумерного вектора, когда все элементы уже известны.

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

int main(){
	vector<vector<int>> v {{1, 0, 1}, {0, 1}, {1, 0, 1}}; 
	for(int i=0;i<v.size();i++){
		for(int j=0;j<v[i].size();j++)
			cout<<v[i][j]<<" ";
		cout<<endl;
	}					   
}

После запуска приведенного выше кода мы получаем следующий вывод:

1 0 1 
0 1 
1 0 1 

Использование vector> символизирует, что мы работаем с вектором векторов. Каждое значение внутри первого набора фигурных скобок, например {1, 0, 1} и {0, 1}, является независимым вектором.

Примечание. Чтобы создать 2D-векторы в C++ с другим типом данных, мы можем поместить тип данных в самые внутренние угловые скобки, например <char>.

Поскольку мы работаем с двумерной структурой данных, нам требуется два цикла для эффективного обхода всей структуры данных. Внешний цикл перемещается по строкам, а внутренний цикл — по столбцам.

Примечание. Функция size() предоставляет количество векторов внутри 2D-вектора, а не общее количество элементов внутри каждого отдельного вектора.

Указание размера для инициализации 2D-вектора

2D-векторы могут быть больших размеров. Мы не можем ожидать, что программист будет вводить каждое отдельное значение. Следовательно, мы можем инициализировать двумерный вектор на основе количества строк и столбцов.

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

int main(){
	//Number of columns
	int num_col = 3;

	// Number of rows
	int num_row = 4;

	// Initializing a single row
	vector<int> row(num_col, 0);

	// Initializing the 2-D vector
	vector<vector<int>> v(num_row, row) ;

	for(int i=0;i<v.size();i++){
		for(int j=0;j<v[i].size();j++)
			cout<<v[i][j]<<" ";
		cout<<endl;
	}					   
}

Результат будет:

0 0 0 
0 0 0 
0 0 0 
0 0 0 

В соответствии со стандартной инициализацией вектора, vector v(10, 0), первый аргумент обозначает размер вектора, тогда как второй обозначает значение по умолчанию, которое содержится в каждой ячейке.

В приведенном выше фрагменте кода мы выполняем два шага стандартной инициализации:

  • vector row(num_col, 0) — в этом операторе мы создаем одномерный вектор с именем row, длина которого определяется num_col и значения по умолчанию 0. По сути, он формирует каждую строку нашего двумерного вектора.
  • vector> v(num_row, row) — в этом операторе мы создаем наш полный двумерный вектор, определяя каждое значение двумерного вектора как row, созданный в последнем операторе.

Поняв описанную выше процедуру, мы можем улучшить нашу инициализацию 2D-векторов в C++ следующим образом:

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

int main(){
	//Number of columns
	int num_col = 3;

	// Number of rows
	int num_row = 4;

	// Initializing the 2-D vector
	vector<vector<int>> v(num_row, vector<int> (num_col, 0)) ;

	for(int i=0;i<v.size();i++){
		for(int j=0;j<v[i].size();j++)
			cout<<v[i][j]<<" ";
		cout<<endl;
	}					   
}

Вышеупомянутый код выдаст такой же вывод, как и раньше, поскольку мы делаем то же самое, но в одной строке кода.

Если мы правильно помним, стандартная инициализация выглядит примерно так, как описано выше. Создание двумерного вектора требует, чтобы мы установили значение по умолчанию для каждого элемента как одномерного вектора.

Последний метод включает создание двумерного вектора без знания строк или столбцов. Это делается:

vector<vector<int>> v;

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

Итераторы для 2D-векторов

Вместо обхода двумерного вектора с использованием индексов в C++ предусмотрены итераторы для каждой конкретной структуры данных STL.

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

int main(){

	vector<vector<int>> v {{1, 0, 1}, {0, 1}, {1, 0, 1}}; 

	// Iterator for the 2-D vector
	vector<vector<int>>::iterator it1;

	// Iterator for each vector inside the 2-D vector
	vector<int>::iterator it2;

	// Traversing a 2-D vector using iterators
	for(it1 = v.begin();it1 != v.end();it1++){
		for(it2 = it1->begin();it2 != it1->end();it2++)
			cout<<*it2<<" ";
		cout<<endl;
	}					   
}

Выход:

1 0 1 
0 1 
1 0 1 

Итераторы пригодятся, когда мы используем определенные операции, требующие аргумента для позиционирования. Две наиболее часто используемые функции, возвращающие значения итератора:

  • v.begin() — возвращает итератор к первому вектору в двумерном векторе.
  • v.end() — возвращает итератор в конец двумерного вектора.

Давайте посмотрим на некоторые операции, возможные на двумерном векторе.

Добавление элементов в двумерный вектор

Чтобы добавить элементы в конец двумерного вектора, мы используем функцию push_back().

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

int main(){

	// Initializing the 2-D vector
	vector<vector<int>> v;

	v.push_back({1, 0, 1});
	v.push_back({0, 1});
	v.push_back({1, 0, 1});

	for(int i=0;i<v.size();i++){
		for(int j=0;j<v[i].size();j++)
			cout<<v[i][j]<<" ";
		cout<<endl;
	}					   
}

Выход:

1 0 1 
0 1 
1 0 1 

Поскольку наш контейнер представляет собой вектор векторов, имеет смысл помещать внутрь него только полные векторы. Следовательно, аргумент, передаваемый внутри функции push_back(), должен быть вектором.

Примечание. v[i] представляет собой одномерный вектор. Поэтому, если программисту необходимо добавить элементы в определенный вектор внутри двумерного вектора, он может использовать v[i].push_back(value).

Чтобы добавить полный вектор в определенное место, мы используем функцию insert().

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

int main(){

	// Initializing the 2-D vector
	vector<vector<int>> v;

	v.push_back({1, 0, 1});
	v.push_back({0, 1});
	v.push_back({1, 0, 1});

	// Iterator for the 2-D vector
	vector<vector<int>>::iterator it = v.begin();

	// Inserting the vector = {1, 2, 3} as the second vector
	v.insert(it + 1, {1, 2, 3});
				  
	for(int i=0;i<v.size();i++){
		for(int j=0;j<v[i].size();j++)
			cout<<v[i][j]<<" ";
		cout<<endl;
	}				   
}

Выход:

1 0 1 
1 2 3 
0 1 
1 0 1 

Функция insert() требует позиционного аргумента в качестве итератора, а не целочисленного индекса. За ним следует вектор, который предполагается вставить в указанное место.

Удаление элементов из 2D-векторов в C++

В отличие от push_back(), C++ предоставляет функцию pop_back(), обязанную удалять последний элемент из заданного вектора.

В контексте этой статьи функция pop_back() будет отвечать за удаление последнего вектора из двумерного вектора.

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

int main(){

	// Initializing the 2-D vector
	vector<vector<int>> v ;

	// Adding vectors to the empty 2-D vector
	v.push_back({1, 0, 1});
	v.push_back({0, 1});
	v.push_back({1, 0, 1});

	// Remove the last vector from a 2-D vector
	v.pop_back();
				  
	for(int i=0;i<v.size();i++){
		for(int j=0;j<v[i].size();j++)
			cout<<v[i][j]<<" ";
		cout<<endl;
	}				   
}

Выход:

1 0 1 
0 1 

В дополнение к функции pop_back() у нас есть функция erase(), с помощью которой мы можем удалять элементы из указанного индекса.

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

int main(){

	// Initializing the 2-D vector
	vector<vector<int>> v ;

	// Pushing vector inside the empty 2-D vector
	v.push_back({1, 0, 1});
	v.push_back({0, 1});
	v.push_back({1, 0, 1});

	// Iterator for the 2-D vector
	vector<vector<int>>::iterator it = v.begin();

	// Remove the second vector from a 2-D vector
	v.erase(it + 1);
				  
	for(int i=0;i<v.size();i++){
		for(int j=0;j<v[i].size();j++)
			cout<<v[i][j]<<" ";
		cout<<endl;
	}				   
}

Выход:

1 0 1 
1 0 1 

Подобно функции insert(), она требует позиционного аргумента в качестве итератора. Чтобы удалить все векторы из двумерного вектора, можно использовать функцию clear().

Приведенных выше функций может быть достаточно, чтобы освоиться при использовании двумерных векторов в C++.

Заключение

Двумерные векторы в C++ очень просты в использовании, при условии, что программист знает используемый синтаксис. Этот тип вектора пригодится, когда мы решаем задачи, связанные с матрицами, графами и другими двумерными объектами.

Мы надеемся, что этот учебник просветил читателя по теме использования 2-D векторов. Не стесняйтесь комментировать ниже любые вопросы, связанные с темой.