C: умный способ «сдвинуть» матрицу? - PullRequest
5 голосов
/ 02 ноября 2010

У меня есть целочисленная матрица, которая должна действовать как буфер:

x = {{0, 0, 0, 0, 0}, {1, 1, 1, 1, 1}, {2, 2, 2, 2, 2}};

Теперь, если я добавлю новую строку {3, 3, 3, 3, 3}, новая матрица должна выглядеть следующим образом:

x = {{1, 1, 1, 1, 1}, {2, 2, 2, 2, 2}, {3, 3, 3, 3, 3}};

Есть ли умный способ сделать это, не копируя все элементы вокруг?

Ответы [ 6 ]

8 голосов
/ 02 ноября 2010

Если ваша матрица определена как int **, и вы отдельно выделяете каждую строку, то вам нужно только поменять местами указатели строк.

6 голосов
/ 02 ноября 2010

Как насчет работы по модулю?

Если вы получаете доступ к элементам как matrix[x + SZ * y], вы можете изменить его на:

matrix[x + SZ * ((y + FIRST_ROW) % SZ)].

Таким образом, чтобы реализовать этот сдвиг, вы просто помещаете новую строку {3, 3, 3 ..} там, где была строка {0, 0, 0}, и увеличиваете счетчик FIRST_ROW, чтобы он указывал на новую начальную строку. .

1 голос
/ 02 ноября 2010

Пример написания ленивого кода - вы можете использовать арифметику по модулю для адресации строк.При нажатии на новую строку, просто увеличьте начальную переменную смещения, добавьте высоту матрицы и модулируйте результат по высоте матрицы.Таким образом, вы получаете круговую матрицу без необходимости копировать всю матрицу и сохранять компактный матричный массив.

1 голос
/ 02 ноября 2010

Если вы используете массив указателей на массивы (а не обычный двумерный массив), вы можете копировать только указатели на строки вместо копирования всех элементов.

И если у вас все в порядке с перераспределением массива указателей, вы можете добавить новый указатель в конец и продвинуть указатель на «начало» массива. Но это не будет хорошей идеей, если вы потенциально захотите сделать такой сдвиг много раз. И, конечно, вы хотели бы убедиться, что у вас есть оригинальный указатель, чтобы вы могли free() ваши ресурсы правильно.

1 голос
/ 02 ноября 2010

Можете ли вы увеличить x так, чтобы он указывал на второй ряд, а затем освободить первый ряд?Очевидно, вам нужно было бы выделять строку за раз, и это не гарантировало бы непрерывность матрицы.Если вам нужно, вы можете выделить один большой блок памяти для хранения вашей матрицы, а затем забить неиспользуемые части, когда достигнете конца.

1 голос
/ 02 ноября 2010

Использовать связанный список.

struct node
{
    int row[5];
    struct node *next;
};

Чтобы добавить строку, достаточно просто пройти список до конца, а затем заменить следующий указатель NULL новым узлом (следующий указатель которого равен NULL).

...