【问题标题】:Arithmetically getting index in 3D vector算术获取 3D 向量中的索引
【发布时间】:2014-02-21 19:44:26
【问题描述】:

我有一个 3d 结构向量。我通过结构的 i j 和 k 来指代结构在 3d 向量中的位置。但是,在制作数百万个这些时,它会占用大量内存,因为该对象存储了太多数据。

如何在不将信息存储在结构本身中的情况下有效地找出特定结构对象的 i,j,k 是什么。我可以用某种记忆算法来做吗?

#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;
}

【问题讨论】:

    标签: c++ optimization memory-management vector struct


    【解决方案1】:

    这就是你要找的吗?您可以将m 视为所有max_i * max_j * max_k 结构的索引。

    这是未经测试的。在 size_t 类型上调用 div 时,您可能需要进行一些转换。

    #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]
    • @BHare 我想我误解了你的问题,所以这个答案可能没有帮助。但是,这带来了一个问题,如果您知道 635454, 4, 3 那么为什么需要引用该结构,因为这些将是您要查找的 i、j、k 值?
    • 据我了解,OP 想知道 i,j,k 只有结构但不将 i,j,k 保留在结构中,例如,检查结构在内存中的位置并找到出数字。
    • 正确。我想知道向量的 i,j,k 索引中的任何特定结构在哪里(如果存在),而不将 i,j,k 存储在结构中
    • @BHare 如果没有溢出风险,您可以使用公式 m = (i*max_j+j)*max_k+k 存储单个数字 m 而不是全部三个 ijk。然后上面的for循环体告诉你如何从m返回ijk
    【解决方案2】:

    有一个非常简单的方法可以用真正的数组来做到这一点。多级std::vector&lt;&gt; 不行,因为所有不同线向量分配的内存不是连续的。但是使用语言的内置数组,这很简单:

    //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] 执行的计算与上面 C++ 示例中myData[getIndex(i, j, k)] 的计算完全相同。而且,和以前一样,您可以使用指针算法检索索引。

    C++ 也有多维数组,但它要求数组维度是编译时常量(你需要使用new 而不是malloc())。在C语言中没有这样的限制,数组大小可以在运行时计算。

    【讨论】:

    • 只有 1 级向量怎么样,使用这样的包装类:位于此处:“class Array3D”stackoverflow.com/questions/2178909/… 是连续的吗?
    • 是的,1 级向量保证是连续的。只有多级不是,因为每个内部向量都会分配自己的一点内存。
    • 我没有将此标记为解决方案,因为它有点不完整。以您提到的方式特别引用不适用于向量,因为它返回一个迭代器和各种混乱。我在让包装器做我想做的事情时遇到问题。
    • 这正是我建议使用矢量的原因。我只是说,向量的记忆是连续的在你问我之后。当然,你总是可以使用&amp;*iterator从迭代器中获取一个指针,不管那个迭代器是什么;但是对于向量,迭代器应该已经是一个指针,您可以使用它来执行所需的所有指针运算(您没有使用反向迭代器,是吗?)。有些人热衷于使用向量和其他 RAII 类型,我不是。但我不想通过警告不要使用向量来不必要地冒犯人们......
    【解决方案3】:

    在您的情况下,您实际上可以通过存储最少量的元数据来相当容易地解决这个问题。

    由于您有两个相对较小的向量,因此可以存储所有 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 变大,它就变得不那么实用了。

    【讨论】:

    • j 和 k 在示例中很小,但除了大于 0 且小于 unsigned long int 之外,它们没有限制。
    • @BHare 那么在寻求帮助时给他们这么小的价值可能不是一个好主意。
    猜你喜欢
    • 2022-06-11
    • 2013-02-13
    • 2018-07-04
    • 2020-03-26
    • 1970-01-01
    • 2021-03-20
    • 2012-11-27
    • 1970-01-01
    • 2014-09-19
    相关资源
    最近更新 更多