У меня есть 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;
}
Существует довольно простой способ сделать это с помощью реальных массивов. Многоуровневый 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 нет такого ограничения, размеры массива могут вычисляться во время выполнения.
В вашем случае вы можете довольно легко понять это, сохранив минимальное количество метаданных.
Поскольку у вас есть два относительно небольших вектора, можно сохранить начальную позицию всех 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 становятся большими.
Это то, что вы ищите? Вы можете считать 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.
}
three_d_struct_v[635454][4][3]