Двумерные матрицы из 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 [3025 просмотров]