| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > Алгоритмы > Транспонирование матрицы |
| Автор: Alagert 8.1.2006, 14:30 |
| Есть прямоугольная матрица, нужно ее траспонировать на месте. Матрица записана построчно в одномерный массив. Для траспонирования нужно использовать этот же массив и можно еще некоторое количество переменных, число которых не зависит от размерности матрицы. Со слов моего препода, понял, что их должно быть 1 или 2. Погите плиз разобраться с этой задачей, очень нужно! Всем спасибо! |
| Автор: maxim1000 8.1.2006, 15:22 |
| ну, например, так: идем по массиву смотрим на очередной элемент массива ищем в массиве то значение, которое там должно быть меняем их друг с другом идем дальше... пример: матрица 2х3 (в одномерном представлении): 1, 2, 3; 4, 5, 6 1-й шаг: смотрим на первый элемент - это (1,1) его не надо менять (так всегда будет на первом шаге) 2-й шаг: смотрим на второй элемент - это (1,2): там стоит 2, а должно быть 4, меняем их местами и так далее на самом деле, если подумать, то алгоритм поиска можно будет заменить на просто вычисление какого-нибудь аналитического выражения, но думать лень |
| Автор: Illuminaty 8.1.2006, 15:25 | ||
| а - массив [0..n], где n = m*m - 1, где m - размерность матрицы temp - переменная транспонирование:
|
| Автор: Alagert 8.1.2006, 16:42 | ||||
Твой вариант проходит для квадратных матриц. С ним все ясно. А как быть с прямоугольной матрицей? |
| Автор: Illuminaty 8.1.2006, 16:53 |
| Alagert, двойку тебе по алгебре в зачетку поставить надо Прямоугольные матрицы не транспонируются |
| Автор: Alagert 8.1.2006, 17:00 | ||
У меня 5 по матану за все курсы Прямоугольная матрица замечательно траспонируется! Была матрица MxN, а стала NxM. Прямоугольные матрицы не обращаются(если не рассматривать случай псевдообратных матриц) |
| Автор: Illuminaty 8.1.2006, 17:28 | ||
|
| Автор: Illuminaty 8.1.2006, 17:54 |
| Признаю ошибку. Мои 5 по алгебре остались в прошлом веке. Действительно, перепутал с обратными... Позор на мою седую голову... Ладно хоть преподаватель не видит по алгебре - его бы удар хватил В связи с этим помогу с алгоритмом, но через некоторое время... |
| Автор: Alagert 8.1.2006, 18:28 | ||
Всем свойственно ошибаться. Огромное спасибо за обещание помочь. |
| Автор: Mal Hack 8.1.2006, 19:34 | ||
| Alagert тут надо еще уже со стороны языка думать, т.к. при транспонировании мтрица получается другой размерности, надо это предусматривать в объявлении переменных. На не надо проссматривать каждый элемент, также можно исключить мнимую диагональ.
|
| Автор: Illuminaty 8.1.2006, 20:09 | ||
Mal Hack, прочитай условие внимательно
|
| Автор: Mal Hack 8.1.2006, 20:42 |
| Illuminaty массив массива строк. Или имеется ввиду вектор? |
| Автор: Alagert 8.1.2006, 20:45 | ||
Для простоты есть интовый массив размерности m*n, туда построчно записана вся матрица. |
| Автор: maxim1000 8.1.2006, 20:56 |
| хм... в том, что я предложил, ошибочка... иногда будет получаться, что число для замены надо взять из уже "отсортированой" части, а значит, что там будут не те числа, которые были изначально... |
| Автор: Mal Hack 8.1.2006, 21:36 | ||
Работает когда m > n, щас думаю над обратным случаем...
|
| Автор: Mal Hack 8.1.2006, 22:01 |
| Alagert уточни в каком именно виде и как хранится матрица, и в каком ее надо записать. |
| Автор: Alagert 8.1.2006, 22:54 | ||
Матрица записана след образом:
т.е была матрица: 1 2 3 4 5 6 записана в массив будет в виде : 1 2 3 4 5 6 после траспонирования: 1 4 2 5 3 6 в массиве будет: 1 4 2 5 3 6 Пасибо за вариант, ща буду его разбирать. |
| Автор: Akina 8.1.2006, 23:20 | ||
| Алгоритм: Исходная матрица - A (M,N) в векторе V (M*N) Конечная матрица - B (N,M) Возьмем элемент вектора V(K). В исходной матрице его адрес: A (K mod N, K div N) В конечной матрице его адрес должен стать: B (K div N, K mod N) Т.е. в векторе V его адрес станет V( N*(K mod N) + (K div N)) Итого:
PS. Писано на коленке, проверьте. |
| Автор: Alagert 8.1.2006, 23:58 | ||||
Работает, если исправить кое что: 1) возьмем V(K), в исходной матр это будет A(K/N, k mod N) 2) в траспонированной B(K mod N, K/N) 3) перестановка в векторе V(M*(K mod N) + K/N) Вот вроде так. В твоем варианте получается, что траспонирование матр никак не зависит от ее второй размерности. 2 Mal Hack В коде, который ты привел ошибка: ты выходишь за границы массива, когда меняешь элементы. И ты принял, что матр квадратная. Ща еще потестирую. ВСЕМ БОЛЬШОЕ СПАСИБО! |
| Автор: Illuminaty 9.1.2006, 01:11 | ||
На тот случай если алгоритм Akina не сработал привожу полную рабочую программу.
|
| Автор: maxim1000 9.1.2006, 01:49 | ||
проблема в том, что тот элемент, на место которого нужно поставить K-й, необязательно должен стать на его место... пример: исходная матрица - 2 строки, 3 столбца 0 1 2 3 4 5 переходит в 0 3 1 4 2 5 например, 1 становится на место 2, но не наоборот... P.S. если не ошибся... |
| Автор: Illuminaty 9.1.2006, 02:07 |
| Почему не будет работать алгоритм Akina. Потому что при транспонировании прямоугольной матрицы элементы не будут заменятся двунаправленно. Т.е. пусть у нас есть матрица: ┌─┬─┬─┐ │0│1│2│ ├─┼─┼─┤ │3│4│5│ └─┴─┴─┘, она транспонируется в матрицу ┌─┬─┐ │0│3│ ├─┼─┤ │1│4│ ├─┼─┤ │2│5│ └─┴─┘, если все записать в строку, то получим, что была строка [0, 1, 2, 3, 4, 5], получили транспонированием строку [0, 3, 1, 4, 2, 5]. Т.е. преобразовния следующие 0 -> 0; 1 -> 2 -> 4 -> 3 -> 1; 5 -> 5; В зависимости от размерности матрицы может быть разное количество таких цепочек. при реализации этих преобразований нужно запомнить, с какими элементами производили преобразования, а с какими - нет. Для этого в моем решении вводится переменная maxmodul, которая хранит максимальный модуль из входной матрицы. Элемент, с которым происвели преобразование, помечаем путем увеличения его модуля на maxmodul + 1. В конце работы, для всех помеченных элементов модуль уменьшаем на maxmodul + 1. Добавлено @ 02:08 maxim1000 немного раньше это написал. Да еще и с тем же примером, что и у меня |
| Автор: maxim1000 9.1.2006, 02:22 | ||
это тоже, как мне кажется, не подходит - при больших значениях оно будет приводить к переполнению операций сложения... на самом деле, это почти эквивалентно использованию старших битов значений... |
| Автор: Illuminaty 9.1.2006, 02:31 |
| maxim1000, можно и тип Real (или double) сделать. Я просто думал над пометкой без использования дополнительных массивов. Насчет переполнения я тоже думал, но ничего другого не придумал. Времени на это не было. И так программу накидал - должен был, а то лопухнулся с определениями. Ладно хоть Alagert не расскажет моему преподавателю по алгебре как лопухнулся. |
| Автор: maxim1000 9.1.2006, 02:40 | ||
помечать элементы никак нельзя - нельзя заставить матрицу хранить больше информации, чем то, насколько она расчитана в случае с double произойдет потеря точности... так что получится ненастоящее транспонирование... Добавлено @ 02:45 вот пришел в голову еще один способ: (для начала сразу скажу - первый индекс - строка или количество строк, второй - столбец или количество столбцов) наша задача - транспонировать матрицу m*n мы точно знаем, какие элементы будут в конце массива - нужно просто взять последний столбец и вытащить его элементы в конец дальше можно отбросить последние m элементы и обработать (n-1)*m матрицу, которая задана в оставшейся части массива... |
| Автор: maxim1000 9.1.2006, 02:58 | ||||||||
вот... правда, тоже писалось на коленках Добавлено @ 03:02
который решает задачу только для некоторых матриц (у которых не слишком большие элементы)
нельзя, т.к.это потребует дополнительных расходов памяти, пропорциональных размерностям матрицы
они сдвинутся под "вытаскиванием" элементов я имел в виду такую операцию - берем элемент, все, которые после него, сдвигаем в сторону начала массива (занимая освободившееся место), а взятый элемент - в конец массива (ну или на каком-то расстоянии от конца) Добавлено @ 03:08 пример с матрицей 2*3 1 2 3 4 5 6 1. вытаскиваем элементы последнего столбца (3 и 6) в конец массива (начиная с нижних) 1.1. вытаскиваем 6 - его вытаскивать не надо, так тут ничего и делать не надо 1.2. вытаскиваем 3: 3 запоминаем (одна временная переменная) 1 2 3 4 5 6 -> 1 2 4 5 (неважно что) 6 -> 1 2 4 5 3 6 Добавлено @ 03:11 а теперь сводим задачу (2*3) к задаче (2*2), уменьшая количество столбцов и размер массива (точнее, размер той части массива, с котороймы работаем), т.е. транспонируем матрицу 2*2: 1 2 4 5 по тому же алгоритму |
| Автор: Mayk 9.1.2006, 09:29 |
| А если менять цепочкой, а не линейно? То есть берем i-ый элемент и ставим его на корректное место j. После этого мы берем не (i+1) элемент(как не единожды предлагалось ранее), а элемент j (то есть тот, на котором должен стоять i). Если же такого уже нет, то берем i+1. При этом i+1 считается обработанным, если в обходе его цепочки мы натолкнемся на обработанный элемент. Цепочка - это... Пример: Есть 123 456 (123456) Хотим 14 25 36 (142536) Отображение A->At такое: 1->1, 2->3, 3->5, 4->2, 5->4, 6->6 Цепочка - это вот такая ерунда: 1->1, 2->3->5->4->2 ну и прочее. Блин. Не могу сформулировать, но интуитивно надеюсь понятно. Запускаем алгоритм: 1) Берем i=1. (123456 <- текущий массив) 2) 1->1. Единица уже была(только что), не меняем (123456) 3) Берем 2. Ставим её на 3. 3 запоминаем (122456) 4) Ставим 3 на 5. 5 запомиаем (122436) 5) Ставим 5 на 4. 4 запоминаем(122536) 6) Ставим 4 на 2. мы начинали с двойки, поэтому останавливаемсч(142536) 7) Берем 3. Мы её не будем трогать, так как цепочка 3->5->4->2 приводит к уже обработанной 2.(142536) 8) Берем 4. Не меняем, так как 4->2 приводит к обработанной 2(142536) 9) Берем 5. Не меняем, так как 5->4 приводит к обработанной 4(142536) 10) Берем 6. Не меняем, так как 6->6 приводит к обработываемой 6(142536) Готово. 142536 Попробую обосновать инвариантом цикла, Инвариант цикла - цепочки всех элементов до текущего оттранспорированны. Инициализация - текущего элемента нет. Предшественников нет. (ну или даже 1-ый элемент всегда оттранспорирован) Сохранения инварианта - мы меняем местами только те элементы, цепочки которых не содержат предшествующих элементов. Иными словами если что-то было верно, то оно останется верным. Если что-то было неверным, оно станет верным. Мы трогаем лишь элементы цепочки. Завершение - Все цепочки оттранспорированны. => оттранспорированны ВСЕ элементы матрицы . ЗЫ. Цепочка образует цикл, это всё очень имхо и это я не доказывал, но имхо это так. Все таки A=Att. Добавлено @ 09:34 Тьфу блин, как же я это такой пост пропустил. Идея с цепочками уже была у Illuminaty Ну ладно. По крайне мере можете попниать обоснование. |
| Автор: Illuminaty 9.1.2006, 10:38 | ||||
| maxim1000, круто! Проверил - действительно работает. Только твоя функция немного неправильно работает, но это из-за
Вот полностью работающая программа
|
| Автор: Alagert 9.1.2006, 11:31 |
| Всем огромное спасибо! А я вот вчера в 1.30 уже сломался. Проверил вариант Akina и бухнулся спать. Сейчас буду разбирать все ваши идеи. |
| Автор: Alagert 9.1.2006, 13:07 |
| Всем огромное спасибо! 2 maxim1000 Спасибо за алг! Все работает. Сам думал сводить задачу к меньшей размерности, но до твоего варианта так и не додумался! 12 числа покажу преподу, реакцию отпишу. Может есть еще легче вариант! |
| Автор: maxim1000 9.1.2006, 15:46 | ||
а, наверное, и не стоит пинать здесь есть одно важное отличие - нет пометки элементов - единственная причина того, что алгоритм работает не для всех случаев так что это, наверное, тоже может быть решением к тому же навскидку мне кажется, что это будет быстрее... |
| Автор: Alagert 12.1.2006, 21:52 |
| Я показал преподу это решение! Он был удивлен, что все это так просто работает! Говорит, что я чего мухлюю! Я рассказал про вариант с цепочками, он сказал, что это гиблое дело. И из этого нормальный алгоритм не выйдет! ЗЫ Может подскажете как автаматически оттестировать этот алг? |
| Автор: Illuminaty 12.1.2006, 22:05 |
| возьми мой код откомпилируй его при преподе запусти и пусть он введет свои данные А на самом деле составь хорошо оформленное математическое доказательство, но это уже в другой раздел.. |
| Автор: myxacuk 16.4.2016, 20:32 |
Модератор: Сообщение скрыто. |