БлогNot. Двумерные матрицы из pair, vector, map и set

Двумерные матрицы из pair, vector, map и set

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

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

Например, пара индексов элементов двумерной матрицы может быть описана как

pair<int, int>

Если "прицепить" к индексам ещё и значение любого нужного типа данных (пусть будет тоже int), получаем структуру

pair<pair<int, int>, int>

для одного элемента целочисленной матрицы, ну а затем можно "сложить" эти элементы в любой удобный контейнер, допустим, в тот же vector:

vector <pair<pair<int, int>, int>> matrix;

Если знать, что образовать пару можно функцией make_pair (first,second), а обращаться к первому и второму членам пары через свойства first и second, работать с контейнером, составленным из пар, становится очень удобно.

В прилагаемой программе показано формирование данных для двумерной целочисленной матрицы на основе трёх самых популярных контейнеров - vector, map и set.

Так как у нас элементы везде одни и те же (1,2,3,...), они корректно запишутся во все три контейнера, на самом деле, выбор контейнера зависит от условия задачи, например, во множество уже встроен контроль уникальности его элементов.

Проверено в консолях Visual Studio 2015 и QT 5.X.

#include <iostream>
#include <iomanip>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <algorithm>
#include <iterator>
using namespace std;

template <class T>
struct printStringIntMap : public unary_function<T, void> {
 ostream & ostr;
 printStringIntMap(ostream &stream) : ostr(stream) {}

 void operator()(const T& item) const {
  ostr << "(" << item.first << ")" << "=" << item.second << endl;
 }
};

int main() {
 //Матрица на основе контейнера vector
 vector <pair<pair<int, int>, int>> matrix;
 const int n = 4, m = 3;
 for (int i = 0; i<n*m; i++) matrix.push_back(make_pair(make_pair(i / m, i%m), i + 1));
 vector <pair<pair<int, int>, int>>::iterator it = matrix.begin();
 for (int i = 0; i < n; i++) {
  for (int j = 0; j < m; j++) cout << setw(3) << (it++)->second
   << "(" << setw(1) << i << "," << setw(1) << j << ") ";
  cout << endl;
 }

 //Она же на map
 map <string, int> matrix2;
 for (int i = 0; i<n*m; i++) {
  string index = to_string(i / m) + "_" + to_string(i%m);
  matrix2.insert(pair<string, int>(index, i + 1));
 }
 map <string, int>::iterator it2;
 for (it2 = matrix2.begin(); it2 != matrix2.end(); ++it2)
  cout << it2->first << ": " << it2->second << endl;

 //Она же на set - будет контроль уникальности элементов
 set <pair<string, int>> matrix3;
 for (int i = 0; i<n*m; i++) {
  matrix3.insert(pair<string, int>(to_string(i / m) + "_" + to_string(i%m), i + 1));
 }
 for_each(matrix3.begin(), matrix3.end(),
  printStringIntMap<map <string, int>::value_type>(cout));

 cin.get(); return 0;
}

Примечания

1. Для вывода в консоль элементов множества set пришлось делать отдельный класс printStringIntMap.

2. Выводить первую матрицу, сделанную на основе контейнера vector, в консоль было необязательно в двойном цикле, можно было обойтись и одним:

vector <pair<pair<int, int>, int>>::iterator it;
 for (it=matrix.begin(); it<matrix.end(); ++it)
  cout << "matrix[" << it->first.first << "," << 
  it->first.second << "]=" << it->second << endl;

3. Обратите внимание, как заполнить двумерную матрицу последовательно идущими значениями 1,2,3,... , применяя только один цикл, приём применим и к "обычной" двумерной матрице:

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

int main() {
 const int n = 4, m = 3;
 int a[n][m];

 //Заполняем матрицу одним циклом
 for (int i = 0; i<n*m; i++) a[i/m][i%m] = i+1;
 
 //Выводим обычным двойным циклом
 for (int i = 0; i < n; i++) {
  for (int j = 0; j<m; j++) cout << setw(3) << a[i][j] << " ";
  cout << endl;
 }

 cin.get(); return 0;
}

Версия без внешнего оператора namespace из Studio 2019 (2022):

#include <iostream>
#include <iomanip>
#include <algorithm>
#include <string>
#include <vector>
#include <map>
#include <set>

int main() {
 const int n = 4, m = 3; //Размерности
 
 //1. Матрица на основе std::vector из std::map<<строка,столбец>,элемент>
 std::vector <std::pair<std::pair<size_t,size_t>,double>> matr;
 for (size_t i = 0; i < n * m; i++) //Заполним значениями 1, 2, ...
  matr.push_back(std::make_pair(std::make_pair(i/m,i%m),i+1));
 //Выведем просто двойным циклом:
 auto it = matr.begin();
 for (size_t i = 0; i < n; i++) {
  for (size_t j = 0; j < m; j++)
   std::cout << std::setw(3) << (it++)->second <<
   " [" << std::setw(1) << i << "," << std::setw(1) << j << "] ";
  std::cout << std::endl;
 }

 //2. Такая же матрица на std::map
 std::map <std::pair<size_t, size_t>, double> matr2;
 for (size_t i = 0; i < n * m; i++)
  matr2.insert(std::make_pair(std::make_pair(i / m, i % m), i + 1));
 auto it2 = matr2.begin();
 for (; it2 != matr2.end(); ++it2) {
  std::cout << std::setw(3) << it2->second <<
   " [" << std::setw(1) << (it2->first).first << "," 
   << std::setw(1) << (it2->first).second << "] " << std::endl;
 }

 //3. Такая же матрица на std::set - будет контроль уникальности элементов
 std::set <std::pair<std::pair<size_t, size_t>, double>> matr3;
 for (size_t i = 0; i < n * m; i++) {
  matr3.insert(std::pair<std::pair<size_t, size_t>,double>
   (std::make_pair(i / m, i % m),i + 1));
 }
 auto it3 = matr3.begin();
 for (; it3 != matr3.end(); ++it3) {
  std::cout << std::setw(3) << it3->second <<
   " [" << std::setw(1) << (it3->first).first << ","
   << std::setw(1) << (it3->first).second << "] " << std::endl;
 }

 return 0;
}

07.05.2019, 16:58 [2873 просмотра]


теги: c++ программирование список

К этой статье пока нет комментариев, Ваш будет первым