Элементарные преобразования матрицы.
Элементарные преобразования используются в методе Гаусса для приведения матрицы к треугольному или ступенчатому виду.
Элементарными преобразованиями строк называют:
Аналогично определяются элементарные преобразования столбцов.
Примеры на элементарные преобразования матрицы
Используя элементарные преобразования строк преобразовать матрицу A в верхнюю треугольную матрицу, где
| A = | 4 | 2 | 0 |
| 1 | 3 | 2 | |
| -1 | 3 | 10 |
поменяем первую и вторую строку местами
ко 2-рой строке прибавим 1-вую, умноженную на -4; к третей строке прибавим первую
2-рую строку поделим на -2, третью строку делим на 6
поменяем вторую и третью строку местами
к 3-тей строке прибавим 2-рую, умноженную на -5
Любые нецензурные комментарии будут удалены, а их авторы занесены в черный список!
Добро пожаловать на OnlineMSchool.
Меня зовут Довжик Михаил Викторович. Я владелец и автор этого сайта, мною написан весь теоретический материал, а также разработаны онлайн упражнения и калькуляторы, которыми Вы можете воспользоваться для изучения математики.
Обмен местами строк матрицы
Необходимо поменять местами две строки матрицы. Нашел в интернете несколько примеров в которых используется поэлементный обмен. Мне такой код не очень нравится, поэтому я написал свой вариант обмена строк матрицы с использованием ссылочных переменных и указателей, но вот беда — я сам не до конца понимаю как он работает ( он работает, проверял на произвольных матрицах ).
(В данном конкретном случае меняю местами строки в зависимости от четности индекса)
Практическим путем выяснил что » *matrix[i] » возвращает значение первого элемента i-ой строки. Честно говоря, не понятно почему так. Знаю, что имя массива это указатель на его первый элемент, видимо, это как-то связано, но точную логическую цепочку не получается провести.
Ссылочная переменная » temp » получает адрес этого первого элемента i-ой строки.
Как работает » matrix[i+1] = &temp; » не очень понятно.
Необходимо поменять местами две строки матрицы.
Во-первых, надо определиться, каким образом объявляется матрица.
Самый простой подход — это объявить матрицу в виде двумерного массива. Например,
В этом случае приведенная вами функция не годится, то есть не будет работать, так как она принимает указатель на указатель в качестве аргумента, а не двумерный массив.
Для вашей функции матрица определяется скорей всего динамически (хотя в частном случае это может быть и локальный массив) как указатель на динамически выделенный одномерный массив, элементы которого в свою очередь являются указателями на динамически выделенные одномерные массивы.
Теперь указатель a можно передать в вашу функцию в качестве первого аргумента.
Внутри этой функции обмениваются соседние элементы динамически созданного массива a , которые являются указателями на первые элементы других выделенных динамически массивов, как
Здесь выражение matrix[i] дает значение элемента, то есть значение указателя, в i-ом элементе массива matrix . Этот указатель содержит адрес первого элемента i-го динамически выделенного массива.
объявляет ссылку на этот первый элемент i-го . Поэтому если взять адрес этого первого элемента, используя ссылку
то значение выражения &item будет равно значению, хранящемся в выражении matrix[i] .
Эквивалентный код может выглядеть следующим образом
Имейте в виду, что есть стандартная функция std::swap , объявленная в заголовке <utility> . которая выполняет данную операцию. С помощью этой функции вы могли бы просто написать
Ниже представлена демонстрационная программа, которая использует два подхода к определению матрицы: первый — в виде массива и второй — в виде набора динамических массивов.
Вывод программы на консоль:
Указатель matrix содержит адрес указателья(является указателем на указатель). matrix[i] это указатель (matrix + i) , *matrix[i] это первый элемент в массиве(строке) matrix + i .
означает, что первому элементу i — той строки придаем имя temp
теперь matrix[i] указывает на начало того же массива, что и matrix[i + 1]
matrix[i+1] = &temp; теперь i + 1 — тый указатель получает значение: адрес первого элемента i — той строки, равно, указывает на строку i
Практически вы могли бы написать функцию проще:
![]()
В представленном коде происходит следующее:
Эта шаблонная функция первым аргументом принимает указатель на указатель на какой-то тип. Судя по всему, предполагается, что этот тип является элементарным. Например, int , float , double .
Исходя из того, что matrix — это указатель на указатель, ваша матрица представлена как массив, в котором хранятся указатели на массивы (строки), в которых хранятся сами элементы:

Где matrix — это указатель, в котором хранится адрес массива ABC ;
Происходит обход всей матрицы по строкам. Здесь сразу видны две проблемы:
- Нет контроля значения переменной rowsQuantity ;
- Переменная типа int не вполне подходит для адресации элементов массива. Переменная типа size_t подойдет гораздо лучше.
Действия выполняются при посещении каждой строки, чей индекс кратен двум (0, 2, 4, и пр.). И действия, соответственно, выполняются попарно над строками 0-1, 2-3, 4-5.Это не совсем рационально, потому что такой подход выполняет в два раза больше инкрементов переменной i , в два раза больше делений с остатком и в два раза больше сравнений, чем реально необходимо.
Гораздо рациональнее было бы выполнять i += 2 , вообще отбросив деление с остатком и проверку. Но такой подход потребует выполнение проверки целочисленного переполнения переменной i .
На первый взгляд, это довольно идиоматическая запись, необходимая для классического обмена местами двух значений с использованием промежуточной переменной:
Но не совсем. Я не уверен до конца, что происходит в недрах компилятора, и что по этому поводу говорит Стандарт .
matrix[i] — получает значение указателя на строку матрицы (адрес массива со значениями строки). * — разыменовывает данный адрес, получая значение (значения) всей строки. По всей видимости, значение строки помещается в ссылочную переменную temp .
Я не специалист по C++ , но мне данный код кажется очень странным. По логике, ссылка является сущностью времени компиляции, иначе говоря — это просто всевдоним для чего-то. То есть, эти три странные строчки можно свести к двум:
В результате чего и в x , и в y будет находится изначальное значение y . Но, по-видимому, компилятор в принципе понимает, что вы от него хотите. А может быть, это неопределенное поведение. Точно сказать не могу, потому что текущий стандарт C++ занимает почти 2000 страниц.
Здесь происходит использование адреса данных, связанных со ссылкой temp .
PS. Я бы рекомендовал как можно реже и меньше смешивать C++ с его C подмножеством. Не потому, что C плохо, а потому что такое смешивание имеет ряд существенных минусов.
Во-первых, низкоуровневая явность C несовместима с высокоуровневой неявностью C++ . Это гарантированно будет приводить к трудным для понимания ошибкам даже во вполне тривиальном коде. Так же это будет вынуждать вас писать еще больше кода, чем при использовании одного только C — вот такой парадокс.
Во-вторых, смешивание ссылок с указателями, шаблонов с макросами и исключений с кодами возврата приводит к неподдающимся анализу ситуациям, потому что названные элементы противоречивы в деталях, хотя поверхностно кажутся очень похожими.
Как в матрице поменять местами строки
Профиль
Группа: Участник
Сообщений: 26
Регистрация: 21.11.2010
Репутация: нет
Всего: нет
Профиль
Группа: Участник
Сообщений: 69
Регистрация: 1.11.2010
Репутация: нет
Всего: 2
| Цитата(Kit0boy @ 25.11.2010, 19:52 ) |
| просто матрицы еще не прошли а задание по ним дают |
Профиль
Группа: Участник
Сообщений: 26
Регистрация: 21.11.2010
Репутация: нет
Всего: нет
Профиль
Группа: Участник
Сообщений: 69
Регистрация: 1.11.2010
Репутация: нет
Всего: 2
| Код |
| int a = 1; int b = 2; |
int temp = a;
a = b;
b = temp;
Профиль
Группа: Участник
Сообщений: 26
Регистрация: 21.11.2010
Репутация: нет
Всего: нет
| Код |
| #include "stdafx.h" #include <cstdlib> #include <stdio.h> #include <iostream> #include <string.h> #include <stdio.h> using namespace std; |
Это сообщение отредактировал(а) Kit0boy — 25.11.2010, 20:21
Профиль
Группа: Участник
Сообщений: 69
Регистрация: 1.11.2010
Репутация: нет
Всего: 2
Профиль
Группа: Участник
Сообщений: 26
Регистрация: 21.11.2010
Репутация: нет
Всего: нет
Профиль
Группа: Участник
Сообщений: 69
Регистрация: 1.11.2010
Репутация: нет
Всего: 2
| Цитата(Kit0boy @ 25.11.2010, 20:23 ) |
| можно просто на ошибки указать? |
| Цитата(Kit0boy @ 25.11.2010, 20:09 ) |
| Код |
| l-=l; k-=k; m=l-k; |
хоть бы откомментировал что-то
Профиль
Группа: Участник
Сообщений: 379
Регистрация: 9.11.2005
Репутация: 26
Всего: 31
| Код |
| #include <iostream> |
using namespace std;
void InputMatrix( int* matrix, int dim )
//функция ввода матрицы размерности dim на dim
<
for( int i = 0; i < dim; i++ )//для каждой строки матрицы
for( int j = 0; j < dim; j++ )//для каждого элемента строки
cin >> matrix[ i * dim + j ];//читаем очередной элемент
>
void PrintMatrix( const int* matrix, int dim )
//функция печати матрицы размерности dim на dim
<
for( int i = 0; i < dim; i++ )//для каждой строки матрицы
<
for( int j = 0; j < dim — 1; j++ )//для каждого элемента строи, кроме последнего
cout << matrix[ i * dim + j ] << " ";//печать очередного элемента и пробел
cout << matrix[ ( i + 1 ) * dim — 1 ] << endl;//печать последнего элемента с переводом строки
>
>
void Swap( int& a, int& b )
//функция обмена двух переменных
<
int temp = a;//запоминаем значение первой переменной
a = b;//первой переменной присваиваем значение второй
b = temp;//значениею второй переменной присваиваем ранее запомненное значение первой
>
void SwapStrings( int* matrix, int dim, int strIndex1, int strIndex2 )
//функция обмена двух строк матрицы с индексами strIndex1, strIndex2
<
for( int i = 0; i < dim; i++ )//для каждого элемента строки
Swap( matrix[ strIndex1 * dim + i ], matrix[ strIndex2 * dim + i ] );//обмениваем значения соответствующих элементов строк
>
int main()
<
int dim, strIndex1, strIndex2;//dim — размерность, strIndex1 и strIndex2 — индексы обмениваемых строк
cout << "Vvedite razmernost matrici:" << endl;
cin >> dim;//ввод размерности матрицы
int* matrix = new int[ dim * dim ];//создаем массив для хранения значений элементов матрицы
cout << "Vvedite indeks 1 stroki dlya obmena:" << endl;
cin >> strIndex1;//ввод 1 индекса строки
cout << "Vvedite indeks 2 stroki dlya obmena:" << endl;
cin >> strIndex2;//ввод 2 индекса строки
cout << "Ishodnaya matrica:" << endl;
PrintMatrix( matrix, dim );//печать исходной матрицы
SwapStrings( matrix, dim, strIndex1, strIndex2 );//обмен строк матрицы
cout << "Matrica posle obmena strok:" << endl;
PrintMatrix( matrix, dim );//печать матрицы результата
delete[] matrix;//удаляем массив
Профиль
Группа: Участник
Сообщений: 26
Регистрация: 21.11.2010
как поменять местами две строки в матрице (в C)?
если вы собираетесь поменять местами строку [0] и строку [1], результирующая матрица будет:
вы можете помочь мне получить для этого код на C?
Это домашнее задание? (отметьте, пожалуйста) — Bob
Это домашнее задание? Как определяется ваша матрица? Вы знаете, как поменять местами две переменные типа int? Вы знаете циклы в C? Проявите немного усилий, и оно будет вознаграждено :). — Maciej Hehl
на самом деле это моя домашняя работа. это единственная оставшаяся матричная операция, которую я не знаю, как решить. матрица [100] [100], но строки и столбцы определяются пользователем. на самом деле я уже закончил замену строк, добавление строк, добавление матриц, мульт. так далее. — user420360
Пожалуйста, поделитесь своими текущими усилиями, чтобы другие могли вам помочь. Без кода никто не знает, на каком элементе проблемы вы застряли. Вы умеете писать for цикл в C? Как задавать умные вопросы:catb.org/esr/faqs/smart-questions.html> Более короткие и ясные версии:dumblittleman.com/2007/10/how-to-ask-smart-questions.html>факультет.gvc.edu/ssnyder/121/Goodquestions.html> — mctylr
спасибо за ссылки mctylr. да, я умею писать для циклов. на самом деле, я пытаюсь понять код обмена строк, а затем просто внести изменения, которые будут соответствовать кодам mt. — user420360
7 ответы
Ответ полностью зависит от того, как реализована ваша «матрица», потому что в языке c такое понятие отсутствует.
Вы используете двумерные массивы?
Или что-то другое?
Двумерные массивы
Придется вручную перемещать отдельные элементы.
(Вот r1 и r2 — это целые числа, которые были установлены в две строки, которые вы хотите поменять местами) или см. Джеймс’ memcpy реализация что вполне может быть быстрее, но требует целых рядов временной памяти.
Рваные массивы
Если эта операция очень распространена и профилирование показывает, что она занимает много времени, вы можете подумать об использовании реализации матрицы с рваным массивом. Что-то вроде этого:
Самое интересное в этой структуре то, что вы все еще можете получить к ней доступ с помощью [][] обозначение, но операция перестановки строк становится
Рваные массивы имеют два недостатка с вашей точки зрения (ну, три из-за проблем с управлением памятью): они требуют дополнительного хранилища для указателей строк, и вы не можете использовать встроенную инициализацию.
Ряд как структура
C не поддерживает присвоение формы массивам;
но это делает поддерживать семантику присваивания по значению для структур. Это дает вам реализацию, предложенную несколькими людьми без объяснения причин:
что гладко. Для этого требуется целый ряд памяти, но, если компилятор хорош, скорее всего, он будет быстрым. Большим недостатком является то, что вы не можете адресовать отдельные элементы матрицы с помощью [][] синтаксиса больше. Скорее ты пишешь m[i].r[j] ;
Другое
Есть много, много других способов реализовать «матрицу» в c, но в большинстве случаев они намного сложнее и полезны только в специализированных ситуациях. К тому времени, когда они вам понадобятся, вы сможете ответить на эти вопросы для себя в контексте каждого из них.
ответ дан 23 мая ’17, 12:05
еще раз спасибо! Я использую 2-й код. однако, когда я попробовал матрицу 2×3, возникла ошибка. третий столбец или столбец [2] не меняются местами. — user420360
я имею в виду, что элементы строки в последнем столбце не меняются местами — user420360
@user обратите внимание на пределы for петля. Если ваши строки имеют длину 3, цикл должен выполняться от 0 до 2, что обычно строится с помощью for(i=0;i<3;++i) . Новички нередко пишут for(i=0;i<2;++i) который не работает или for(i=0;i<=2;++i) что будет, но выглядит странно (не идиоматично) для программистов на C. — dmckee — котенок экс-модератора
Я понял это в цикле for. я user420360
ответ дан 23 авг.
Хороший. Самое приятное здесь то, что он работает для любой реализация с непрерывными строками. — dmckee — котенок экс-модератора
Хороший ответ, хорошее использование typedef, чтобы сделать код более читабельным. Но я боюсь, что это, скорее всего, не отвечает на OP, так как я подозреваю, что это просто идет ему в голову. — мактилр
Большое спасибо за ответ. Я новичок в C, и мы еще не закончили обсуждение с memcpy — user420360
Я бы, вероятно, поменял местами по одному элементу, чтобы не использовать много дополнительного хранилища. Если вы работаете в основном с такими вещами, как графические преобразования, где матрицы обычно имеют размер 3×3 или 4×4, подход Джеймса Каррана следующий: вероятно Немного лучше. Если вы работаете (или можете работать) с действительно большими матрицами, это сэкономит память и, возможно, будет работать быстрее:
ответ дан 23 авг.
решить это твое домашнее задание?
ответ дан 23 авг.
Вы должны добавить сюда обсуждение; Тем более, что это вопрос новичка. Этот трюк работает из-за семантики присваивания структур. — dmckee — котенок экс-модератора
Обмен выглядит неплохо. Но это: row[1].m[2] = . отстой. Хм, в том-то и дело, не так ли? — Мацей Хель
@Maciej a #define здесь помогает — user411313
Значит, дело было не в этом. Вы действительно хотели, чтобы ответ был полезным, а не просто озорной попыткой наказать ОП? Я бы не догадался. — Мацей Хель
Эй! Это мой первый пост о переполнении стека, я знаю, что он довольно длинный, надеюсь, меня не забанят!
Вероятно, одним из самых элегантных подходов было бы использование функции, которая меняет местами два полученных аргумента, используя ее для обмена компонентами матрицы. Скажем что-нибудь вроде своп (а, б). Как уже многие говорили, мы должны рассмотреть возможность использования вспомогательной переменной
Недавно я освоил новый метод, который показался мне впечатляющим, с использованием побитовой операции XOR (http://en.wikipedia.org/wiki/Xor) таким образом вспомогательный не нужен
Вы можете легко использовать эту операцию, чтобы поменять местами два элемента (a и b) — я считаю, что это не по теме, но я настоял на этой идее, потому что мне это показалось довольно интересным. Наконец, отвечая на ваш вопрос, вы можете использовать, скажем,
при наличии матрицы, объявленной как
Вы можете использовать свой способ XOR для замены строк, сначала идентифицируя элементы, которые необходимо заменить (в соответствии с индексом строки, как вы уже сказали)
Надеюсь, это будет полезно в вашей дальнейшей практике.
Также попробуйте этот пример, я уверен, что впоследствии вы поймете всю идею намного лучше (не забывайте, что индекс матрицы начинается с 0!)