Арифметически получаемый индекс в трехмерном векторе

0

У меня есть 3d-вектор структур. Я ссылаюсь на то, где структура находится в 3d-векторе по структуре ij и k. Однако, когда вы делаете миллионы, он занимает кучу памяти, потому что объект хранит так много данных.

Как я могу эффективно определить, какой i, j, ka конкретный объект структуры не хранит эту информацию в самой структуре. Могу ли я сделать это с какой-то арифметикой памяти?

#include <iostream>
#include <vector>
#include <string>

using namespace std;

int main() {
    struct MyStruct {
        size_t i;
        size_t j;
        size_t k;
        bool some_bool;
    };

    vector<vector<vector<MyStruct>>> three_d_struct_v;

    size_t max_i = 1000000;
    size_t max_j = 10;
    size_t max_k = 10;

    for(size_t i = 0; i < max_i; i++) {
        for(size_t j = 0; j < max_j; j++) {
            for(size_t k = 0; k < max_k; k++) {
                three_d_struct_v.emplace_back(MyStruct{i,j,k,false});
            }
        }
    }


    return 0;
}
Теги:
optimization
struct
vector
memory-management

3 ответа

1
Лучший ответ

Существует довольно простой способ сделать это с помощью реальных массивов. Многоуровневый std::vector<> не будет делать, потому что память, выделенная всеми разными линейными векторами, не является непрерывной. Но со встроенными массивами языка это довольно просто:

//Get the memory
bool myData* = new bool[max_i*max_j*max_k];
inline size_t getIndex(size_t i, size_t j, size_t k) { return (i*max_j + j)*max_k + k; }
inline size_t getI(size_t index) { return index/max_j/max_k; }
inline size_t getJ(size_t index) { return (index/max_k)%max_j; }
inline size_t getK(size_t index) { return index%max_k; }

Теперь вы можете говорить об индексах так же, как вы могли бы говорить о указателях на ваши структуры. Если вы действительно должны сделать это C++, вы можете преобразовать ссылки и индексы следующим образом:

bool& referenceToElement = myData[anIndex];
size_t recoveredIndex = &referenceToElement - myData;

Однако в C вы можете сделать гораздо лучше:

bool (*myData)[max_j][max_k] = malloc(max_i*sizeof(*myData));
myData[i][j][k] = true;    //True 3D array access!

Расчет, выполненный myData[i][j][k], точно такой же, как и вычисление myData[getIndex(i, j, k)] в примере C++ выше. И, как и прежде, вы можете получить индекс, используя арифметику указателя.

C++ также имеет многомерные массивы, но для измерения размеров массива требуются константы времени компиляции (и вам нужно использовать new вместо malloc()). В C нет такого ограничения, размеры массива могут вычисляться во время выполнения.

  • 0
    А как насчет вектора 1 уровня, использующего класс-оболочку, такой как этот: расположенный здесь: "class Array3D" stackoverflow.com/questions/2178909/… Это непрерывно?
  • 0
    Да, вектор 1 уровня гарантированно будет смежным. Только многоуровневого нет, потому что каждый внутренний вектор будет выделять свой маленький кусочек памяти.
Показать ещё 2 комментария
0

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

Поскольку у вас есть два относительно небольших вектора, можно сохранить начальную позицию всех j/k комбинаций.

size_t max_i = 1000000;
size_t max_j = 10;
size_t max_k = 10;

Вы захотите реструктурировать свои векторы, которые будут сохранены [k] [j] [i]. Если вы сохраняете 100 возможных комбинаций j/k на std :: map, то вы можете найти значения j/k, найдя самый большой адрес, меньший, чем адрес вашего вектора. Оттуда вы вычисляете смещение в байтах и делите на размер вашей структуры, чтобы выяснить i.

Это становится гораздо менее практичным, если max_j и max_k становятся большими.

  • 0
    j и k в этом примере малы, но не имеют ограничений, кроме того, что они больше 0 и меньше, чем unsigned long int.
  • 0
    @BHare, тогда, вероятно, не очень хорошая идея, чтобы дать им такие маленькие значения при обращении за помощью.
0

Это то, что вы ищите? Вы можете считать m индексом всех max_i * max_j * max_k structs.

Это не проверено. Возможно, вам придется выполнять кастинг при вызове div по типам size_t.

#include <cstdlib> // divmod

size_t max_i = 1000000;
size_t max_j = 10;
size_t max_k = 10;

size_t N = max_i * max_j * max_k; // beware of overflow

for( size_t m=0 ; m<N ; ++m )
{
    div_t q = div( m, max_k );
    size_t k = q.rem;

    q = div( q.quot, max_j );
    size_t j = q.rem;

    q = div( q.quot, max_i );
    size_t i = q.rem;

    // Now i, j, k are set. Do as thou shall.
}
  • 0
    Мне трудно после этого. Как это может помочь мне ссылаться на конкретную структуру? Допустим, я хочу сослаться на three_d_struct_v[635454][4][3]
  • 0
    @BHare Я думаю, что я неправильно понял вашу проблему, поэтому этот ответ не может быть полезным. Однако возникает вопрос: если вы знаете 635454, 4, 3, тогда зачем вам ссылаться на структуру, так как это будут значения i, j, k, которые вы ищете?
Показать ещё 3 комментария

Ещё вопросы

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