On-line: гостей 0. Всего: 0 [подробнее..]
Программисты всех стран, объединяйтесь!

АвторСообщение



ссылка на сообщение  Отправлено: 20.10.18 17:27. Заголовок: Выполнение инверсии строк матрицы или в частном случае двух-мерного массива.


Эта тема создана на основе вопроса на 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 предложения на основе диапазона на вызов стандартного алгоритма std::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


Спасибо: 0 
ПрофильЦитата Ответить
Новых ответов нет


Ответ:
1 2 3 4 5 6 7 8 9
большой шрифт малый шрифт надстрочный подстрочный заголовок большой заголовок видео с youtube.com картинка из интернета картинка с компьютера ссылка файл с компьютера русская клавиатура транслитератор  цитата  кавычки моноширинный шрифт моноширинный шрифт горизонтальная линия отступ точка LI бегущая строка оффтопик свернутый текст

показывать это сообщение только модераторам
не делать ссылки активными
Имя, пароль:      зарегистрироваться    
Тему читают:
- участник сейчас на форуме
- участник вне форума
Все даты в формате GMT  3 час. Хитов сегодня: 22
Права: смайлы да, картинки да, шрифты да, голосования нет
аватары да, автозамена ссылок вкл, премодерация откл, правка нет