Как бы я go обратил 2D массив в C? - PullRequest
0 голосов
/ 12 февраля 2020

Допустим, мой массив выглядит следующим образом. Количество строк всегда будет соответствовать количеству столбцов в этой программе.

[0] [1] [2]
[3] [4] [5]
[6] [7] [8]

Мне нужно преобразовать это в обратную форму:

[2] [1] [0]
[5] [4] [3]
[8] [7] [6]

Я знаю, что многомерные массивы просто массивы массивов, которые, я надеюсь, сокращают масштаб моего вопроса до простого обращения к одномерному массиву, но я не знаю, как применить ту же идею к двумерному массиву. Размер не всегда будет размером 3 на 3, но строки и столбцы всегда будут одинаковыми.

Ответы [ 3 ]

2 голосов
/ 12 февраля 2020

Если вы ищете функцию для обращения к двумерному массиву, вы можете использовать объявление функции, например: void reverse_2d_arr(int , int (*)[]);

где,

void reverse_2d_arr(int size, int arr[size][size]) {
    int i = 0, j, k, temp;
    while(i < size) {
        j = 0;
        k = size - 1;
        while(j < k) {
            temp = arr[i][j];
            arr[i][j] = arr[i][k];
            arr[i][k] = temp;
            k--;
            j++;
        }
        i++;
    }
}

и вызывать его, используя: reverse_2d_arr(3, arr); где arr - ваш 2d массив, а 3 - его размер.

1 голос
/ 12 февраля 2020

Попробуйте следующий код, здесь n - количество строк, а m - количество столбцов. Надеюсь, это решит вашу проблему. Удачного кодирования!

for(i = 0; i < n; i++) {
    for(j = 0; j < m/2; j++) {
        int temp = arr[i][j];
        arr[i][j] = arr[i][m-j-1];
        arr[i][m-j-1] = temp;
    }
}
0 голосов
/ 12 февраля 2020

Использование стандартных массивов

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

void rev2d (int (*a)[COLS], int rows, int cols)
{
    for (int i = 0; i < rows; i++)
        for (int j = 0, k = cols - 1; j < k; j++, k--) {
            int tmp = a[i][j];
            a[i][j] = a[i][k];
            a[i][k] = tmp;
        }
}

(выше ..[j] и ..[k] elemnts каждый поменяется местами на каждую итерацию inner-l oop)

Или если вы хотите сделать то же самое, используя while циклы и указатели на начальный и конечный элементы в каждой строке (кроме итерации по строкам в обратном порядке) вы можете сделать следующее:

void rev2dptrs (int (*a)[COLS], int rows, int cols)
{
    while (rows--) {
        int *beg = *(a + rows), *end = *(a + rows) + cols - 1;
        while (end > beg) {
            int tmp = *beg;
            *beg++ = *end;
            *end-- = tmp;
        }
    }
}

В каждом случае, например, если у вас есть:

#define ROWS 3
#define COLS ROWS
...
    int a[][COLS] = {{ 0, 1, 2 }, { 3, 4, 5 }, { 6, 7, 8 }};

Ваш вызов функции будет:

    rev2d (a, ROWS, COLS);

или во втором случае:

    rev2dptrs (a, ROWS, COLS);

Просто поворот при нормальном развороте.

Использование массивов переменной длины

Первоначальная цель состояла в том, чтобы избежать примеров с VLA из-за C11 Standard - 6.7.6.2 Деклараторы массивов (p4) "Variable length arrays are a conditional feature that implementations need not support;" и C11 Standard - 6.10.8.3 Макросы условных функций __STDC_NO_VLA__

Однако, как указано в комментариях, и с практикой реального мира Поскольку практически все основные компиляторы будут продолжать предоставлять VLA, вы можете обеспечить немного большую гибкость, изменив декларации и указав размеры rows и cols fist, а затем передав массив в виде VLA. Преимущество в том, что оно освобождает вас от постоянного размера. Например, но функции можно переписать, передав массив в виде VLA:

void rev2dvla (int rows, int cols, int a[rows][cols])
{
    for (int i = 0; i < rows; i++)
        for (int j = 0, k = cols - 1; j < k; j++, k--) {
            int tmp = a[i][j];
            a[i][j] = a[i][k];
            a[i][k] = tmp;
        }
}

и с указателями:

void rev2dptrsvla (int rows, int cols, int a[rows][cols])
{
    while (rows--) {
        int *beg = *(a + rows),
            *end = *(a + rows) + cols - 1;
        while (end > beg) {
            int tmp = *beg;
            *beg++ = *end;
            *end-- = tmp;
        }
    }
}

Здесь преимущество состоит в том, что вы освобождаетесь от целого числа постоянное ограничение на количество элементов в строке. При указании параметров rows и cols перед параметром массива значения rows и cols становятся известны до того, как массив int a[rows][cols] задан в качестве параметра, позволяющего VLA иметь полный тип.

В этом случае вызовами функций будут:

    rev2dvla (rows, COLS, a);

и

    rev2dptrsvla (rows, COLS, a);

Если вы понимаете каждый из способов и чем они отличаются от других - тогда у вас есть сортировка 2D массив под контролем. Дайте мне знать, если у вас есть дополнительные вопросы.

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

#include <stdio.h>

#define COLS 3

void rev2d (int (*a)[COLS], int rows, int cols)
{
    for (int i = 0; i < rows; i++)
        for (int j = 0, k = cols - 1; j < k; j++, k--) {
            int tmp = a[i][j];
            a[i][j] = a[i][k];
            a[i][k] = tmp;
        }
}

void rev2dptrs (int (*a)[COLS], int rows, int cols)
{
    while (rows--) {
        int *beg = *(a + rows),
            *end = *(a + rows) + cols - 1;
        while (end > beg) {
            int tmp = *beg;
            *beg++ = *end;
            *end-- = tmp;
        }
    }
}

void rev2dvla (int rows, int cols, int a[rows][cols])
{
    for (int i = 0; i < rows; i++)
        for (int j = 0, k = cols - 1; j < k; j++, k--) {
            int tmp = a[i][j];
            a[i][j] = a[i][k];
            a[i][k] = tmp;
        }
}

void rev2dptrsvla (int rows, int cols, int a[rows][cols])
{
    while (rows--) {
        int *beg = *(a + rows),
            *end = *(a + rows) + cols - 1;
        while (end > beg) {
            int tmp = *beg;
            *beg++ = *end;
            *end-- = tmp;
        }
    }
}

void prn2d (int (*a)[COLS], int rows, int cols)
{
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++)
            printf (" %2d", a[i][j]);
        putchar ('\n');
    }
}

int main (void) {

    int a[][COLS] = {{ 0, 1, 2 }, { 3, 4, 5 }, { 6, 7, 8 }},
        rows = sizeof *a / sizeof **a;

    puts ("original:");
    prn2d (a, rows, COLS);          /* print original */

    rev2d (a, rows, COLS);          /* reverse col values using indexes */
    puts ("\nreversed using indexes:");
    prn2d (a, rows, COLS);          /* print reversed array */

    rev2dptrs (a, rows, COLS);      /* reverse reversed array to restore original */
    puts ("\nrestore original using pointers:");
    prn2d (a, rows, COLS);          /* print original */

    rev2dptrs (a, rows, COLS);      /* reverse col values using pointers */
    puts ("\nreverse again using pointers:");
    prn2d (a, rows, COLS);          /* print reversed array */

    rev2dvla (rows, COLS, a);       /* reverse col values restoring original */
    puts ("\nrestore original using VLA w/indexes:");
    prn2d (a, rows, COLS);          /* print original */

    rev2dvla (rows, COLS, a);       /* reverse col values using indexes */
    puts ("\nreversed with VLA using indexes:");
    prn2d (a, rows, COLS);          /* print reversed array */

    rev2dptrsvla (rows, COLS, a);   /* reverse reversed array to restore original */
    puts ("\nrestore original using VLA w/pointers:");
    prn2d (a, rows, COLS);          /* print original */

    rev2dptrsvla (rows, COLS, a);   /* reverse col values using pointers */
    puts ("\nreverse again using VLA w/pointers:");
    prn2d (a, rows, COLS);          /* print reversed array */
}

Пример использования / Вывод

$ ./bin/revarr2d
original:
  0  1  2
  3  4  5
  6  7  8

reversed using indexes:
  2  1  0
  5  4  3
  8  7  6

restore original using pointers:
  0  1  2
  3  4  5
  6  7  8

reverse again using pointers:
  2  1  0
  5  4  3
  8  7  6

restore original using VLA w/indexes:
  0  1  2
  3  4  5
  6  7  8

reversed with VLA using indexes:
  2  1  0
  5  4  3
  8  7  6

restore original using VLA w/pointers:
  0  1  2
  3  4  5
  6  7  8

reverse again using VLA w/pointers:
  2  1  0
  5  4  3
  8  7  6
...