Эта тема создана на основе вопроса на Stackoverflow
How to swap rows or columns in a two dimensional array? Автор вопроса спрашивает, как выполнить инверсию строк или колонок матрицы. В заголовке вопросе он ссылается на двух-мерный массив хотя в приведенном примере кода, включенном в вопрос, он имеет дело не с двух-мерным массивом, а с динамически созданном массивом массивов. А также его пример имеет дело лишь с проблемой выполнения инверсии строк матрицы, а не колонок.
Поэтому именно инверсия строк матрицы и будет рассмотрена в этой теме.
Автор вопроса приводит пример того, что он хочет получить. То есть если имеется матрица вида
1 1 1 1 1
2 2 2 2 2
3 3 3 3 3
4 4 4 4 4
5 5 5 5 5
то нужно получить матрицу вида
5 5 5 5 5
4 4 4 4 4
3 3 3 3 3
2 2 2 2 2
1 1 1 1 1
Очевидно, для начинающего программиста это задание на умение использовать обычные
for-циклы. Но в данной теме рассмотрим, как можно выполнить поставленное задачу с использованием стандартных алгоритмов вместо циклов.
Для начала рассмотрим, как сделать инверсию строк именно для двух-мерного массива.
Практически, все задание можно выполнить с помощью стандартных алгоритмов.
Ниже представлена демонстрационная программа для данного случая.
#include <iostream>
#include <iterator>
#include <algorithm>
int main()
{
const size_t N = 5;
int a[N][N];
int i = 1;
for ( auto &row : a ) std::fill( std::begin( row ), std::end( row ), i++ );
for ( const auto &row : a )
{
std::copy( std::begin( row ), std::end( row ), std::ostream_iterator<int>( std::cout, " " ) );
std::cout << '\n';
}
std::cout << '\n';
std::reverse( std::begin( a ), std::end( a ) );
for ( const auto &row : a )
{
std::copy( std::begin( row ), std::end( row ), std::ostream_iterator<int>( std::cout, " " ) );
std::cout << '\n';
}
std::cout << '\n';
}
Вывод программы на консоль:
1 1 1 1 1
2 2 2 2 2
3 3 3 3 3
4 4 4 4 4
5 5 5 5 5
5 5 5 5 5
4 4 4 4 4
3 3 3 3 3
2 2 2 2 2
1 1 1 1 1
То есть используя стандартный алгоритм
std::reverse для двух-мерного массива, можно выполнить инверсию его строк, так как функция
std::swap также определена для массивов.
В этой программе можно было бы также заменить все
for предложения на основе диапазона на вызов стандартного алгоритма s
td::for_each. Например, вывод массива на консоль можно было бы сделать следующим образом
auto display_row = []( const auto &row )
{
std::copy( std::begin( row ), std::end( row ), std::ostream_iterator<int>( std::cout, " " ) );
std::cout << '\n';
};
std::for_each( std::begin( a ), std::end( a ), display_row );
std::cout << '\n';
Однако следует не увлекаться вызовом алгоритма
std::for_each вместо использования предложения
for на основе диапазона. Иногда код с использованием предложения
for на основе диапазона выглядит более ясным и читабельным, чем использование алгоритма
std::for_each, когда объект функции, используемый в этом алгоритме, является чрезмерно сложным и громоздким.
Теперь рассмотрим, случай, имеющий место в исходном вопросе, когда динамически создается массив массивов. В этом случае программа усложняется тем, что нужно выделить память для массивов и затем не забыть ее удалить. Но и в этом случае достаточно применить алгоритм
std:;reverse для элементов "внешнего" массива, которые имеют тип указателей.
Ниже представлена соответствующая демонстрационная программа.
#include <iostream>
#include <iomanip>
#include <memory>
#include <iterator>
#include <algorithm>
#include <cstdlib>
#include <ctime>
int main()
{
size_t n, m;
std::cout << "Enter the number of rows n = ";
std::cin >> n;
std::cout << "Enter the number of columns m = ";
std::cin >> m;
std::cout << '\n';
std::srand( ( unsigned int )std::time( nullptr ) );
int **a = new int *[n];
std::generate( a, a + n, [=] { return new int[m]; } );
std::for_each( a, a + n,
[=]( auto row )
{
std::generate( row, row + m, [=] { return std::rand() % ( n * m ); } );
} );
auto display_row = [=]( auto row )
{
std::for_each( row, row + m,
[]( const auto &value ){ std::cout << std::setw( 2 ) << value << ' '; } );
std::cout << '\n';
};
std::for_each( a, a + n, display_row );
std::cout << '\n';
std::reverse( a, a + n );
std::for_each( a, a + n, display_row );
std::cout << '\n';
std::for_each( a, a + n, std::default_delete<int>() );
delete []a;
}
Вывод программы на консоль может выглядеть следующим образом:
Enter the number of rows n = 5
Enter the number of columns m = 5
19 1 12 21 23
8 11 24 24 2
6 9 12 11 18
3 8 21 5 24
2 10 17 23 7
2 10 17 23 7
3 8 21 5 24
6 9 12 11 18
8 11 24 24 2
19 1 12 21 23