Транспонирование матрицы в C++

Я пишу программу для транспонирования заданной матрицы с использованием выделенной памяти. Функция отлично работает с квадратной матрицей NxN (строки==столбцы), но падает с матрицей MxN (строки != столбцы). Пожалуйста помоги

void transpose(int **matrix, int *row, int *col)
{
    // dynamically allocate an array
    int **result;
    result = new int *[*col]; //creates a new array of pointers to int objects
    // check for error
    if (result == NULL)
    {
        cout << "Error allocating array";
        exit(1);
    }
    for (int count = 0; count < *col; count++)
    {
        *(result + count) = new int[*row];
    }

    // transposing
    for (int i = 0; i<*row; i++)
    {
       for (int j = i+1; j<*col; j++)
       {
        int temp = *(*(matrix + i) + j);
        *(*(matrix + i) + j) = *(*(matrix + j) + i);
        *(*(matrix + j) + i) = temp;
       }
    }

    for (int i = 0; i<*row; i++)
    {
       for (int j = 0; j<*col; j++)
       {
          *(*(result + i) + j) = *(*(matrix + i) + j);
          cout << *(*(result + i) + j) << "\t";
       }
       cout << endl;
    }
}

person Casper    schedule 13.02.2013    source источник
comment
new выдает исключение при сбое. Используйте new(nothrow), если вы хотите, чтобы он возвращал null в случае ошибки (хотя это необычно).   -  person Peter Wood    schedule 13.02.2013


Ответы (2)


Линии:

for (int i = 0; i<*row; i++)
{
   for (int j = i+1; j<*col; j++)
   {
    int temp = *(*(matrix + i) + j);
    *(*(matrix + i) + j) = *(*(matrix + j) + i);
    *(*(matrix + j) + i) = temp;
   }
}

являются проблемой. Проблема в том, что матрица индексируется i, затем j, а не j, как я, как вы делаете во второй и третьей строке цикла while. Представьте, что матрица представляет собой матрицу 2x3, затем вы пытаетесь выполнить матрицу[2][3] = матрица[3][2], но матрица[3][2] не существует.

Лучше всего просто инициализировать результат непосредственно в этом цикле:

for (int i = 0; i<*row; i++)
   for (int j = 0; j<*col; j++)
     result[j][i] = matrix[i][j];

Затем вы можете вывести, как показано ниже, или удалить матрицу и переназначить матрицу, чтобы получить результат по вашему желанию. Вся моя функция транспонирования стала следующим кодом (строка и столбец не должны быть указателями на передачу int по значению, это нормально. Также доступ к матрицам должен использовать индексы массива, так как это более приятный стиль):

void transpose(int **matrix, int row, int col)
{
  // dynamically allocate an array
  int **result;
  result = new int *[col]; //creates a new array of pointers to int objects
  for (int i = 0; i < col; i++)
    result[i] = new int[row];

  // transposing
  for (int i = 0; i<row; i++)
   for (int j = 0; j<col; j++)
     result[j][i] = matrix[i][j];

  //output resulting matrix
  for (int i = 0; i<col; i++) {
   for (int j = 0; j<row; j++)
    cout << result[i][j] << "\t";
   cout << endl;
  }
}
person pippin1289    schedule 13.02.2013
comment
это было из ваших выходных заявлений? потому что вам нужно убедиться, что эти циклы одинаково индексируют результат, вместо *row по *col они должны быть *col по *row - person pippin1289; 13.02.2013
comment
Я добавил всю свою функцию транспонирования, которую я тестировал - person pippin1289; 13.02.2013
comment
@pippin1289 не забудьте удалить выделенную память - person borisbn; 13.02.2013
comment
о, это еще один вопрос, я собирался спросить, нужно ли мне освобождать этот массив результатов, в моем учебнике, когда они используют функцию возврата и используют выделенный массив памяти, я не вижу, чтобы они вызывали delete[] array , но я думаю, что каждый раз мы используем ключевое слово new для выделенного массива памяти, нам нужно его освободить, верно? - person Casper; 13.02.2013
comment
Конечно, вам нужно будет удалить его. Я не был уверен в том, чего вы на самом деле хотели от результата. Вы можете вернуть его, если хотите использовать, или вы можете удалить матрицу и переназначить результат. В любом случае при удалении матрицы вы должны перебирать первый массив, вызывая delete[] для каждого подмассива, а затем finsih с помощью delete[] для всей матрицы. - person pippin1289; 13.02.2013
comment
для приведенной выше функции результат состоит в том, чтобы просто удерживать массив, а затем распечатывать его, как это делают коды, у меня также есть другие функции, которые возвращают указатели, и в этих функциях я также создал новый динамический массив памяти. Так мне нужно освободить их в обоих видах функций void и **int ? - person Casper; 14.02.2013
comment
Если вы возвращаете указатель, вы не можете освободить память в функции, иначе вы вернете мусорную память или ноль. Если вы не возвращаете никакого значения, вам определенно следует освободить память внутри функции. Просто будьте осторожны с функциями, возвращающими только что выделенную память, чтобы обязательно удалить их, когда они больше не используются. - person pippin1289; 14.02.2013

Вы пытаетесь транспонировать матрицу «на месте»:

((матрица + i) + j) = ((матрица + j) + i);

Вы не должны этого делать. Если количество столбцов больше, чем количество строк, выделенных для matrix, вы будете читать и записывать нераспределенную память.

ИМХО, лучше всю матрицу хранить в непрерывной памяти. Не в разных частях. Таким образом, код будет выглядеть так:

void transpose( int *matrix, int row, int col )
{
    for ( int i = 0; i < row; i++ )
    {
       for ( int j = i + 1; j < col; j++ )
       {
           int temp = matrix[ i * col + j ];
           matrix[ i * col + j ] = matrix[ j * col + i ];
           matrix[ j * col + i ] = temp;
       }
    }
}

Единственный минус этого распределения, что вы не можете адресовать элемент типа matrix[ i ][ j ], а только matrix[ i + col + j ]. Плюсы: 1) простота выделения/освобождения памяти (просто matrix = new int[ col * row ] и delete [] matrix) 2) чуть более быстрый доступ к элементам (из-за непрерывного их расположения)

В конце концов, я думаю, что это был бы лучший способ взглянуть на std::vector. Если хотите, я могу показать вам, как ваша функция будет выглядеть с вектором

person borisbn    schedule 13.02.2013
comment
да, спасибо за ваш вклад, мне много раз говорили, что использование вектора намного лучше, но для этой проблемы мне необходимо использовать эту концепцию :( - person Casper; 13.02.2013