Лучший способ придать многомерному массиву нечетные размеры в C ?

#c #syntax #multidimensional-array #dimensions

#c #синтаксис #многомерный массив #размеры

Вопрос:

Я написал следующую функцию, чтобы придать объекту двумерного массива нечетные размеры, добавив строку или столбец по мере необходимости (где sizeX, sizeY, get, set и resize являются понятными функциями-членами grid2D).

 void makeOdd(grid2D<double> *pSrc)
// ---------------------------------------------------------------------------------------------------------
// Make one or both dimensions of input array odd (via row/column copy).
{

    // Variable declarations
    grid2D<double> pTmp = *pSrc;                                // Scratch local source variable
    int simax, sjmax;                                               // Source dimensions

    // Get source dimensions
    sjmax = pSrc->sizeY();
    simax = pSrc->sizeX();

    // Check if source is already odd-dimensioned
    if (sjmax%2 amp;amp; simax%2) return;

    // Extend row/column of source if necessary
    if (sjmax%2 amp;amp; !(simax%2))                                      // Odd rows, even columns
    {
        pSrc->resize(simax 1,sjmax);                                // Resize source with extra column
        for(int i=0; i<simax 1; i  )
        {
            for(int j=0; j<sjmax; j  )
            {
                if(i==simax)
                    pSrc->set(i,j,pTmp.get(simax-1,j));             // Copy last column
                else
                    pSrc->set(i,j,pTmp.get(i,j));
            }
        }
        return;
    }
    else if (!(sjmax%2) amp;amp; simax%2)                                 // Even rows, odd columns
    {
        pSrc->resize(simax,sjmax 1);                                // Resize source with extra row
        for(int i=0; i<simax; i  )
        {
            for(int j=0; j<sjmax 1; j  )
            {
                if(i==simax)
                    pSrc->set(i,j,pTmp.get(i,sjmax-1));             // Copy last row
                else
                    pSrc->set(i,j,pTmp.get(i,j));
            }
        }
        return;
    }
    else                                                            // Even rows, even columns
    {
        pSrc->resize(simax 1,sjmax 1);                              // Resize source with extra row and column
        for(int i=0; i<simax 1; i  )
        {
            for(int j=0; j<sjmax 1; j  )
            {
                if(i==simax amp;amp; j==sjmax)
                {
                    pSrc->set(i,j,pTmp.get(simax-1,sjmax-1));       // Copy last column and row
                }
                else if(i==simax amp;amp; j<sjmax)
                {
                    pSrc->set(i,j,pTmp.get(simax-1,j));             // Copy last column
                }
                else if(i<simax amp;amp; j==sjmax)
                {
                    pSrc->set(i,j,pTmp.get(i,sjmax-1));             // Copy last row
                }
                else
                {
                    pSrc->set(i,j,pTmp.get(i,j));
                }
            }
        }
        return;
    }

}
  

Мой вопрос: есть ли более чистый / эффективный способ сделать это?

Большое спасибо…

Комментарии:

1. Что именно вы пытаетесь здесь сделать?

2. Например, если у меня есть двойной массив X размером 10×10, я хочу, чтобы X имел размер 11×11, скопировав последнюю строку и столбец, чтобы создать новые размеры.

Ответ №1:

Я думаю, было бы проще сначала проверить количество строк и при необходимости увеличить его на 1. Затем проверьте количество столбцов и при необходимости увеличьте каждый из них на 1.

Предполагая, что ваш grid2d является оболочкой вокруг vector<vector<T> > , вы можете передать значение resize , которое оно будет использовать для заполнения вновь созданного пространства, поэтому, когда вы добавляете строку, вы можете просто передать текущую последнюю строку, чтобы скопировать ее в новую последнюю строку.

Ответ №2:

Ваш код IMO довольно запутан для этой проблемы… Я бы сделал вместо

 void makeOdd(grid2D<double> *pSrc)
{
    int ny = pSrc->sizeY();
    int nx = pSrc->sizeX();
    int oddnx = nx   (nx % 2 == 0);
    int oddny = ny   (ny % 2 == 0);
    if (nx != oddnx || ny != oddny)
    {
        pSrc->resize(oddnx, oddny);
        if (nx != oddnx)
            for (int y=0; y<ny; y  )
                pSrc->set(nx, y, pSrc->get(nx-1, y));
        if (ny != oddny)
            for (int x=0; x<oddnx; x  )
                pSrc->set(x, ny, pSrc->get(x, ny-1));
    }
}
  

Конечно, в зависимости от grid2D это могло бы быть еще проще, если бы знать внутреннюю структуру объекта вместо использования общедоступного интерфейса resize / get / set (например, путем создания makeOdd метода).

Кстати, в вашем исходном коде вы создаете копию pTmp указателя (не исходного объекта); и это тоже бессмысленно.

Комментарии:

1. Привет 6502, Большое спасибо за чистый и сжатый код! Что касается вашего второго пункта, я определил оператор «=» внутри grid2D для сохранения rhs в новый контейнер T (здесь double), чтобы операция не была бессмысленной.

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

3. Привет, 6502, еще раз спасибо за ответ. В моей функции-члене grid2D «resize» я удаляю контейнер <double> и выделяю новый контейнер <double> нового указанного размера. Как вы предлагаете это сделать, чтобы сохранить исходное содержимое?

4. Упс. Я думал, что изменение размера позволяет сохранить содержимое (как и для стандартных контейнеров). Если ваша реализация вместо этого просто удаляет все содержимое, то, по крайней мере, вам следует изменить имя на что-то вроде recreate или zap . Как написать эффективную операцию изменения размера с сохранением содержимого (IMO очень полезно в целом), конечно, зависит от того, каково внутреннее представление: является ли оно одиночным std::vector<T> с вычисляемым индексом или std::vector<std::vector<T> > ? это разреженный массив std::map<std::pair<int, int>, double> ?

5. Контейнерная сетка 2D проста: int grid_size_x, int grid_size_y, int grid_size и T* grid (где T обычно равно <double>). Хранимые данные (некоторые данные дистанционного зондирования) могут быть любыми — от нулевых до полностью заполненных данными, в зависимости от условий. Обязательным требованием является максимально быстрый доступ к данным. Вы предлагаете векторы для этого?