Учитывая 2D массив, конвертировать в Z-порядок

0

У меня возникли проблемы с переносом головы вокруг этого преобразования. Я хочу рекурсивно преобразовать 2D-матрицу NxN в свою версию z-order.

Например, заданный массив:

[ 1  2 ]
[ 3  4 ]

Z-порядок

[ 1 2 3 4] 

Каковы рекурсивные шаги для преобразования z-порядка?

Теги:
multidimensional-array
matrix

2 ответа

2

Рекурсивный способ прост:

  • посетить верхний левый
  • посетить верхний правый
  • посетить нижний левый
  • посетить нижний правый

В коде

#include <iostream>

template<typename M, typename CBACK>
void zorder(const M& m, int y0, int x0, int size,
            CBACK cback)
{
    if (size == 1) {
        // Base case, just one cell
        cback(m[y0][x0]);
    } else {
        // Recurse in Z-order
        int h = size/2;
        zorder(m, y0,   x0,   h, cback); // top-left
        zorder(m, y0,   x0+h, h, cback); // top-right
        zorder(m, y0+h, x0,   h, cback); // bottom-left
        zorder(m, y0+h, x0+h, h, cback); // bottom-right
    }
}

void print(int x) {
    std::cout << x << " ";
}

int main(int argc, const char *argv[]) {
    int x[][4] = {{ 1,  2,  3,  4},
                  { 5,  6,  7,  8},
                  { 9, 10, 11, 12},
                  {13, 14, 15, 16}};
    zorder(x, 0, 0, 4, print);
    std::cout << std::endl;
    return 0;
}

Вывод этой программы

1 2 5 6 3 4 7 8 9 10 13 14 11 12 15 16

Обратите внимание, что существует и другой нерекурсивный подход: для посещения элементов в z-порядке вы можете просто перебирать счетчик и принимать нечетные биты как y и четные биты как x (подсчет бит от 0):

int zorder_x_of(int index) {
    int x = 0;
    for (int b=0,k=0; (1<<b) <= index; b+=2,k++) {
        x += ((index & (1<<b)) != 0) << k;
    }
    return x;
}

int zorder_y_of(int index) {
    return zorder_x_of(index>>1);
}

template<typename M, typename CBACK>
void zorder2(const M& m, int size, CBACK cback)
{
    for (int i=0; i<size*size; i++) {
        cback(m[zorder_y_of(i)][zorder_x_of(i)]);
    }
}

Заметка:

В приведенных выше образцах кода я создал функцию, которая принимает "обратный вызов" (называемый cback), который будет вызываться с элементами матрицы, по одному за раз в z-порядке.

Чтобы разрешить использование как в качестве матрицы, так и как функцию обратного вызова, которая поддерживает двойную [] индексацию и все, что можно назвать, я использовал шаблон C++.

В основной программе в качестве матрицы я использовал двумерный массив целых чисел и функцию, но код мог бы скомпилироваться, например, с помощью std::vector< std::vector< double > > качестве матрицы и объекта экземпляр класса, предоставляющего operator()(double) качестве обратного вызова.

  • 0
    Спасибо за помощь. Попытка понять использование CBACK, если вы не против разработки.
  • 1
    @Derptacos: я добавил пояснение к параметру cback но, конечно, один SO-ответ не является cback местом для объяснения метапрограммирования шаблонов C ++. Если вы ничего не знаете об этом, я бы посоветовал немного изучить эту тему, потому что шаблоны могут быть мощным оружием в некоторых случаях. Имейте в виду, однако, что существует серьезный риск быть втянутым в фетишизм шаблонов, когда шаблон злоупотребляет далеко за пределами здравого смысла и где даже глупости, такие как boost.spirit, кажутся разумными инструментами.
0

2D-матрица ведет себя внутренне как 1D-массив, то есть уже находится в "Z-порядке".

Просто перебирайте указатель, указывающий на первый элемент до NxM где N - количество столбцов, а M - количество строк.

пример:

int arr[2][2] = {{2,4},{3,5}};
for (int i=0; i<2 * 2; ++i){
    std::cout << *(&arr[0][0] + i);  // or *(arr + i)
}

Ещё вопросы

Сообщество Overcoder
Наверх
Меню