【问题标题】:Using multiple keys with map/unordered_map (multidimensional)使用带有 map/unordered_map 的多个键(多维)
【发布时间】:2014-03-22 01:45:12
【问题描述】:

Consier 我有一些桶 (vector<float>)。我需要根据一些索引访问这个存储桶。示例:

int indexX, indexY, indexZ, indexW;

因此,当一个新点到达时,我需要将该点放入正确的存储桶中。现在我正在做这样的事情:

//            X                  Y                  Z                  W   => Bucket
unordered_map<int, unordered_map<int, unordered_map<int, unordered_map<int, vector<float>>>>> indexedTable;

// New point arrives and I put it in the right bucket:
indexedTable[indexX][indexY][indexZ][indexW].push_back(myValue);

但我觉得这很丑陋,而且很遗憾它也很慢。比如访问1700点,需要0.56秒,太慢了。

在不使用 Boost 的情况下,有没有更好/更快的替代方案?
请注意,我需要的这种数据结构与稀疏矩阵(多维)相当,因为很少有“桶”会被填充。

【问题讨论】:

    标签: c++ map hashmap


    【解决方案1】:

    您可以使用 unordered_map 和包含 4 个索引的 struct 作为键,并使用 vector&lt;float&gt; 作为值类型,而不是使用这个 4 深的怪物。为该结构提供一个相等比较器和哈希函数,您就可以开始工作了。

    struct indices
    {
        int indexX, indexY, indexZ, indexW;
    
        bool operator==(indices const& other) const
        {
            return std::tie(indexX, indexY, indexZ, indexW) ==
                   std::tie(other.indexX, other.indexY, other.indexZ, other.indexW);
        }
    };
    
    struct indices_hash
    {
        std::size_t operator()(indices const& i) const
        {
            std::size_t seed = 0;
            boost::hash_combine(seed, i.indexX);
            boost::hash_combine(seed, i.indexY);
            boost::hash_combine(seed, i.indexZ);
            boost::hash_combine(seed, i.indexW);
    
            return seed;
        }
    };
    
    std::unordered_map<indices, std::vector<float>, indices_hash> m;
    

    由于您不想使用 Boost,请提出您自己的 hash_combine 替代方案或从 here 复制实现。

    Live example

    【讨论】:

    • 我会包含一个 indices 的构造函数,它接受所有 4 个参数,并且我会为 std::hash&lt;indices&gt; 提供一个特化,因此您不必在 @987654330 中显式命名哈希@.
    • @Praetorian:我将从那里复制 hash_combine,但是 hash_value() 函数呢? seed ^= **hash_value(v)** + 0x9e3779b9 + (seed &lt;&lt; 6) + (seed &gt;&gt; 2);
    • @llnk 改用std::hash&lt;T&gt;{}(v)。
    • 我离开了hash_value(),好像已经在std::中定义了
    【解决方案2】:

    只要您不需要访问一个维度内的所有点(即所有 y==2 的桶),那么您应该考虑使用单个结构来表示您的点,而不是嵌套地图。

    类似的东西:

    struct Point_t
    {
        int x;
        int y;
        int z;
        int w;
        Point_t (int _x, int _y, int _z, int _w) : x (_x), y (_y), z (_z), w (_w) {}
    };
    
    // Make sure the points are sortable
    struct CmpPoint_t
    {
        bool operator() (const Point_t& lhs, const Point_t& rhs)
        {
            return (lhs.x < rhs.x &&
                    lhs.y < rhs.y &&
                    lhs.z < rhs.z &&
                    lhs.w < rhs.w);
        }
     };
    
    typedef std::vector<float> Bucket_t;
    typedef std::map<Point_t, Bucket_t, CmpPoint_t> BucketMap_t;
    

    应用您的示例用例:

    BucketMap_t indexedTable;
    indexedTable[Point_t(indexX, indexY, indexZ, indexW)].push_back (myValue);
    

    【讨论】:

    • 非常好的解决方案。但是为什么我需要那个比较功能呢?如果我使用 unordered_map 我不需要对它们进行排序......?我相信您只需要 == 运算符,例如@Pretorian
    • 在地图中,您的键必须有一个operator&lt;,以便它们可以被排序。对于 unordered_map,您必须提供 operator== 实现以及散列函数。使用 unordered_map,哈希函数的质量会影响性能。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-11-09
    • 1970-01-01
    • 2018-10-07
    • 2011-04-17
    • 1970-01-01
    • 2021-06-03
    相关资源
    最近更新 更多