0 / 0 / 0
Регистрация: 16.11.2016
Сообщений: 10
|
|
1 | |
Выполнить операцию транспонирования прямоугольной матрицы A16.08.2017, 10:14. Показов 3525. Ответов 30
Метки нет (Все метки)
Выполнить операцию транспонирования прямоугольной матрицы A(m,n),m<>n , не выделяя дополнительного массива для хранения результата. Матрицу представить в виде одномерного массива.
0
|
16.08.2017, 10:14 | |
Ответы с готовыми решениями:
30
Выполнить операцию транспонирования прямоугольной матрицы Выполнить операцию транспонирования прямоугольной матрицы Выполнить операцию транспонирования прямоугольной матрицы Выполнить операцию транспонирования прямоугольной матрицы A (m, n), m ≠ n, не выделяя дополнительного массива для хранен |
200 / 87 / 9
Регистрация: 15.11.2010
Сообщений: 472
|
|||||||||||
16.08.2017, 12:59 | 3 | ||||||||||
Romadxd!
Не понятно, а можно ли вообще эту задачу решить в общем случае. Ведь матрицы могут быть не квадратными, что значит, что разные измерения у них имеют разную длину. Т. е. возможна матрица , у которой . Тогда является матрицей, у которой, n строк и m столбцов, т. е. . Если мы захотим представить двумерные матрицы двумерными массивами (самый естественный способ), то двумерный массив с размерностью никак не будет работать как массив с размерностью , устройство сишного массива (да и не только сишного) этого не позволяет. А после транспонирования именно это и должно произойти с этим массивом, ведь мы же хотим, чтобы результат транспонирования матрицы оказывался в том же массиве, что и исходная матрица. Можно, конечно, взять указатель и выделить для него память в куче под ячеек. Доступ к этим ячейкам будет как в одномерном массиве, но зато этот участок памяти можно трактовать и как массив с размерностью , и как массив с размерностью , и в нём выполнить соответствующие перестановки элементов. Я подумал сейчас, можно, наверное, и с двумерным массивом попробовать провернуть этот трюк через приведение типов массивов или указателей. Но с этим будет потом всё равно так неудобно работать, потому что массив останется с прежней исходной размерностью: не заменится у массива волшебным образом на . Можно ещё использовать объединение — тип union, и объявить в нём два массива — один с одной размерностью, другой с обратной.
Так что определись, что у тебя за задача и что тебе на самом деле нужно. Если это задание в учебном заведении, надо уточнить, что имел в виду преподаватель. Добавлено через 23 минуты Попробовал сейчас это сделать, написав следующую программу.
тип массива в операции приведения типа Значит, стандарт языка такого не позволяет. Остаётся изворачиваться только через указатели. А вообще в задаче немного смысла. Задача (транспонировать матрицу, записывая результат в неё же саму) имеет смысл для квадратной матрицы, у которой обе размерности равны. Там она действительно просто решается.
2
|
41 / 38 / 22
Регистрация: 02.04.2016
Сообщений: 131
|
||||||
16.08.2017, 18:13 | 4 | |||||
Если я всё правильно понял, то вот так:
1
|
Диссидент
27709 / 17325 / 3811
Регистрация: 24.12.2010
Сообщений: 38,979
|
|
16.08.2017, 22:09 | 5 |
JohnyWalker, mid150, А вы это видели?
И задача - пустяк. Небольшая игра с индексами, которая лично мне не прибавит ума. А вам может быть и интересна, и забавна.
Добавлено через 2 минуты А вот заголовок темы
0
|
41 / 38 / 22
Регистрация: 02.04.2016
Сообщений: 131
|
|
17.08.2017, 06:47 | 6 |
Байт, мне думается, что нужно представлять в виде одномерного массива уже транспонированную матрицу, то есть ту, что получаем на выходе, то есть просто строка из символов входящих в матрицу. Если очень нужно, можно объявить таковой массив,заполнить его, а только потом выводить. Однако, так как одномерный массив в программе более негде не фигурирует, кроме как на выводе, то особого смысла в его объявлении я не вижу.
0
|
200 / 87 / 9
Регистрация: 15.11.2010
Сообщений: 472
|
|
17.08.2017, 09:23 | 7 |
Нет, этого я не заметил. Иначе не написал бы свой пост №3.
Действительно можно взять одномерный массив размерностью M*N и рассматривать его и как двумерный [M][N], и как двумерный [N][M]. Добавлено через 58 минут В общем, Байт, условие задачи понятно (оно вполне корректно после твоего уточнения), а как решить её, я не знаю. Сходу простого решения в голову не приходит.
1
|
Диссидент
27709 / 17325 / 3811
Регистрация: 24.12.2010
Сообщений: 38,979
|
||||||
17.08.2017, 09:50 | 8 | |||||
JohnyWalker, Элемент [i][j] в линейном представлении будет иметь индекс M*j + i
Транспонирование, это обмен [i][j] - [j][i]
Проверьте, пожалуйста. (Если не лень)
3
|
200 / 87 / 9
Регистрация: 15.11.2010
Сообщений: 472
|
||||||||||||||||||||||||||
17.08.2017, 13:42 | 9 | |||||||||||||||||||||||||
Байт, проверил я твой пример очень тщательно. Не работает он. Твой вариант, это самое первое, что приходит в голову, и оно в общем-то работает для квадратных матриц. Но для прямоугольных матриц с разными размерами сторон оно работать не будет. Вот я сделал несколько тестов.
1. Твой алгоритм для прямоугольной матрицы размерностью 3*5. Кликните здесь для просмотра всего текста
Он работает неправильно. Числа оказались на самых разных местах. 2. Тот же алгоритм, но для квадратной матрицы. Кликните здесь для просмотра всего текста
Мы в результате преобразования получили исходную матрицу. В этом нет ничего удивительного, поскольку перестановка элементов [i,j] <--> [j,i] для любой пары i != j при таком алгоритме выполняется дважды — один раз в виде [i,j] <--> [j,i], а второй раз в виде [j,i] <--> [i,j]. Это двойное транспонирование, т. е. , т. е. тождественное преобразование. 3. Исправленный и работающий алгоритм для квадратных матриц будет выглядеть так Кликните здесь для просмотра всего текста
В таком виде он работает правильно. 4. Пробуем этот исправленный алгоритм применить к прямоугольной не квадратной матрице, хотя в этом смысла особого нет. Кликните здесь для просмотра всего текста
Видим, что он не работает. 5. Пробуем тот же алгоритм 4., но в слегка изменённом виде Кликните здесь для просмотра всего текста
Этот вариант тоже не работает, хотя где-то правильные куски в получившейся матрице и есть (но их очень мало). Тут дело в том, что при записи в массив портятся входные данные (исходная матрица), а форматы обеих матриц очень разные (они имеют разную размерность - M*N и N*M), что не позволяет таким простым способом побороть этот эффект. Можешь все эти тесты странслировать у себя и убедиться, что это так, а заодно проверить, нет ли в них ошибок. Эта задача не такая простая и она совсем не программистская, а скорее математическая. Это задача на перестановки элементов. Это маленькая головоломка. Может, она и имеет простое изящное решение, но я его не вижу.
2
|
Диссидент
27709 / 17325 / 3811
Регистрация: 24.12.2010
Сообщений: 38,979
|
|
17.08.2017, 21:36 | 10 |
JohnyWalker, да, вы правы. Погорячился я. Не так все просто. И работа вами проделана большая.
По поводу двойного транспонирования - мой несомненный ляп. Но вот тут имхо, вы не правы Вот матрица (строка) ( 1, 2) Вот она же транспонированная (столбец) 1 2 Самая обычная математическая операция. Часто используемая. Сейчас нет особого настроения и времени, но обещаю заняться этим вопросом и свою ошибку исправить в ближайшее время Добавлено через 17 минут JohnyWalker, Посмотрел на примере 2 х 3 1 2 3 4 5 6 Линейная запись 1 2 3 4 5 6 Транспонированная 1 4 2 5 3 6 Линейная запись 1 4 2 5 3 6 Любопытная перестановка. Закон пока не улавливается. Думать надо.
1
|
200 / 87 / 9
Регистрация: 15.11.2010
Сообщений: 472
|
|
17.08.2017, 21:39 | 11 |
Там структура всего этого сложная и запутанная. Квадратная матрица симметричная (в смысле равенства своих сторон, а не в том смысле, что под этим понимают в линейной алгебре, конечно), и исходная, и результирующая транспонированная матрица естественно ложатся друг на друга. Поэтому простейший алгоритм и работает. А вот когда матрица прямоугольная, но не квадратная, и при этом обе матрицы с противоположным значением размеров должны находиться в одном буфере, не ложатся они так легко друг на друга. При их наложении возникает путаница и полное несоответствие одного другому. Поэтому и не проходит этот алгоритм в такой простой форме. Вы можете попробовать решить эту задачу, но это явно головоломка. Я с ней не стал разбираться, она не такая простая. На решение таких головоломок может уйти и месяц, и никакой гарантии, что до него додумаешься. И при этом практической пользы в задаче никакой. Может, она и очень просто решается, может, и нет. В общем, это головоломка на перестановки элементов. Сам этим не хочу заниматься. Вы можете попробовать чисто из спортивного интереса, не более.
2
|
Байт
|
17.08.2017, 21:42
#12
|
1
|
200 / 87 / 9
Регистрация: 15.11.2010
Сообщений: 472
|
|
17.08.2017, 21:43 | 13 |
А впрочем, если задача вам нравится с чисто математической стороны, попробуйте из любви к искусству. Почему бы и нет
Ха... В приведённом вами примере закон как раз есть. Приглядитесь ближе Только как его использовать...
1
|
Диссидент
27709 / 17325 / 3811
Регистрация: 24.12.2010
Сообщений: 38,979
|
|
18.08.2017, 10:03 | 14 |
Немного подумав, пришел к таким выводам.
Пусть матрица A[N][M] представлена в линейной записи C[N*M]. Напечатать как матрицу А, так и матрицу транспонированную - тривиальная задача. Столь же тривиальна задача - создать линейное представление D[M*N] транспонированной матрицы (в другой области памяти) Задача существенно усложняется, если запрещается использование дополнительной памяти. И дело здесь не в вычислении линейного индекса на основе двойного, а в необходимости производить циклические перестановки довольно замысловатого вида. Возможно, в решении этой задачи могла бы оказать помощь и Алгебра (Теория Групп, например) Я все-таки не оставляю надежды, разобраться с этой задачей....
0
|
17 / 16 / 3
Регистрация: 18.08.2017
Сообщений: 54
|
||||||||||||||||
19.08.2017, 09:20 | 15 | |||||||||||||||
2x2 http://ideone.com/ip7v3i
Кликните здесь для просмотра всего текста
Код
1 2 3 4 1 3 2 4 1 2 3 4 3x2 http://ideone.com/3ItZB3 (лень копипастить) 4x2 http://ideone.com/Be9u6F Кликните здесь для просмотра всего текста
Код
1 2 3 4 5 6 7 8 1 3 5 7 2 4 6 8 1 2 3 4 5 6 7 8 Код int_rotate списан с http://en.cppreference.com/w/c... ementation . Впрочем, здесь не нужна настолько общая реализация вращения. Функция int_rotate используется чтобы промежуток [a, b, c, ... , d, e] превратить в [e, a, b, c, ... , d] . Достаточно написать более понятную специальную функцию, реализующую данную перестановку.Добавлено через 16 минут Впрочем, код не работает *yawn* Добавлено через 4 часа 12 минут Так получше: http://ideone.com/AoBHbB Кликните здесь для просмотра всего текста
Протестировал почти на всех комбинациях N×M от 1×1 до 5×5, для которых N*M <= 16; Специалистам по теории групп оставляю оптимизацию алгоритма (или доказательство того, что он оптимален). Добавлено через 16 часов 41 минуту Алгоритм, кстати, крайне неоптимален. Для него число swap -ов для матрицы N×M равно в точности произведению (N-1)-го на (M-1)-й треугольных чисел: . Если подставить определение треугольных чисел, или . Короче, число обменов растёт как .Вот таблица для некоторых малых размеров матриц. В таблице указано число обменов. Видно, что для матрицы 5×5 оно уже равно 100. Добавлено через 11 минут Если вместо циклических сдвигов использовать только swap для элемента, стоящего не на своём месте с элементом, который должен быть на его месте, то тогда нужно гораздо меньше swap -ов. См. таблицу.Проблема в том, что для циклических перестановок алгоритм определения границ промежутка, который надо вращать, весьма прост. А вот как реализовать оптимальный алгоритм — пока непонятно. Что интересно, даже изменение числа перестановок с ростом одной из размерностей матрицы при фиксированной другой немонотонно!
2
|
Диссидент
27709 / 17325 / 3811
Регистрация: 24.12.2010
Сообщений: 38,979
|
|
19.08.2017, 09:26 | 16 |
УГнетатель, правильно ли я понял ваш алгоритм? (если неправильно, прошу прощения, смотрел ваш код вскользь)
В функции int_rotate для циклического сдвига на k позиций вы k раз делаете циклический сдвиг на 1 позицию. Это так, или мне показалось? Если действительно так, то можно существенно оптимизировать код. Если мне показалось, то еще раз прошу прощения.
0
|
17 / 16 / 3
Регистрация: 18.08.2017
Сообщений: 54
|
|
19.08.2017, 09:56 | 17 |
Байт, как я уже писал, реализация int_rotate слизана с std::rotate, с небольшими изменениями, связанными с тем, что я не возвращаю из int_rotate ничего. Похоже, что http://en.cppreference.com/w/c... ementation удовлетворяет требованиям к complexity, так что для int_rotate complexity должна быть такой же, как для std::rotate: линейной по размеру промежутка, который циклически сдвигается. Независимо от того, на какое число позиций производится сдвиг.
Оптимизации int_rotate отдельно тут не помогут. Оптимизировать надо весь алгоритм транспонирования с учётом того, что вращение используется только для того, чтобы поставить один элемент на правильное место (иногда на место встаёт более одного элемента, но это случается нечасто). Остальные элементы гоняются почём зря, ещё и по нескольку раз, т.к. вращаемые промежутки часто перекрываются. Но, как я уже писал, закон нахождения места для вставки элемента и вставляемого элемента при использовании циклических сдвигов очень прост, в этом преимущество такого подхода.
2
|
Диссидент
27709 / 17325 / 3811
Регистрация: 24.12.2010
Сообщений: 38,979
|
|
19.08.2017, 23:00 | 18 |
УГнетатель, имхо, весь алгоритм не должен быть сложнее, чем O(M*N)
Но я пока не вижу способа обойтись без вспомогательного массива битов. Тут получаются циклические перестановки элементов, но надо знать, какие элементы матрицы уже переставлены. Возможно, есть вполне определенный способ (математический) увидеть "корни" этих перестановок, но я его пока не нащупал.
0
|
17 / 16 / 3
Регистрация: 18.08.2017
Сообщений: 54
|
|
20.08.2017, 16:09 | 19 |
Байт, в общем, я прекратил попытки решить эту задачу более оптимально самостоятельно и полез в википедию. Там пишут, что наиболее оптимальные из известных алгоритмов работают за O(NM log (NM)). Причём, если я правильно понял, это с использованием дополнительной памяти.
Правда, http://www.netlib.org/utk/peop... talk35.pdf тут вроде как решают задачу за O(NM) при O(1) по памяти, переставляя в цикле. Я тоже нашёл приведённую там формулу вычисления следующего элемента цикла по текущему как "текущий*M mod (N*M - 1)". Только в случае, когда цикл замкнётся, т.е. мы получим начальный элемент цикла (например, единицу, если мы начали переставлять с единицы) не совсем понятно, как назначить следующий элемент в качестве "текущего", т.е начать другой цикл. Сколько я не бился, закономерностей не видно. Видимо, O(NM) при O(1) по памяти у авторов это при конкретном размере матрицы, когда нам известно число циклов и их начальные элементы. А в общем случае нужно сколько-то дополнительной памяти для того, чтобы проверять, что мы начинаем новый цикл, а не попадём в один из старых циклов. Добавлено через 8 минут http://on-demand.gputechconf.c... cesses.pdf тут O(N*M) при O(max(N,M)) доп. памяти. В принципе, неплохо.
1
|
738 / 543 / 416
Регистрация: 17.09.2015
Сообщений: 1,601
|
||||||
20.08.2017, 19:16 | 20 | |||||
попытался реализовать логику перебора массива не подряд,а по цепочке тех элементов которые должны меняться местами, arr[0][1] исходной матрицы переходит в arr[1][0] транспонированной матрицы,который соответствует arr[3] в одномерном массиве (или arr[0][3] исходной матрицы),значит следующим будет arr[3][0] транспонированной матрицы, который соответствует arr[9] в одномерном массиве (или arr[1][4] исходной матрицы), следующим будет arr[4][1] транспонированной матрицы, и т.д.
работает не на всех размерах(на четных,смешанных и больших не корректно) и нуждается в доработке
1
|
20.08.2017, 19:16 | |
20.08.2017, 19:16 | |
Помогаю со студенческими работами здесь
20
Выполнить операцию транспонирования матрицы Выполнить операцию сглаживания матрицы Выполнить обработку элементов прямоугольной матрицы Выполнить обработку элементов прямоугольной матрицы Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |