【问题标题】:Which data structure should i use for my purpose? [duplicate]我应该使用哪种数据结构来实现我的目的? [复制]
【发布时间】:2013-06-03 08:38:55
【问题描述】:

我需要一个像地图一样的数据结构,但每个键可能有多个与之相关的值,但我需要将与单个键对应的所有值作为对象数组获取。那么哪种数据结构最好做到这一点。我不需要在数据结构中搜索,我只需要快速访问与特定键对应的所有值。我查看了 std::multimap 但它没有返回特定键的所有值。那么我可能会使用哪种 C++ 中最好的数据结构?

【问题讨论】:

  • std::map<key_type, std::vector<value_type>>.
  • 顺便说一句,multimap 可以通过键返回值,而不是在数组中,但可以。 cplusplus.com/reference/map/multimap/equal_range
  • @ForEveR,是的,我知道,但想知道是否存在将所有值作为数组返回的东西
  • 为什么需要将值作为数组?
  • 如果我向您解释整个事情会更好。我有一个 3D 网格,现在我有许多由一组点组成的不同形状的单元格。现在我需要知道所有具有特定点的单元格的索引。所以我在地图中的“键”将是该点的索引,而我的“值”应该是共享该点的所有单元格的索引。现在我不想一次又一次地迭代 std::map,因为我有大约 8000 万个这样的点需要填充地图。我希望你能理解我想要表达的意思

标签: c++ data-structures c++11 map multimap


【解决方案1】:

我需要一个像地图一样的数据结构,但是......

std::map<key, std::vector<value>>

8000 万点是一个不错的选择 - 值得考虑其他选择。值得思考/实验/基准测试的包括:

  • 稀疏直接索引...要实现这一点,您不仅需要足够的内存来存储 8000 万个数据点,还需要它们跨越的整个 x/y/z 空间,然后可以执行[x][y][z]查找单元格 id 的向量 - 这显然会很大 - 从您的问题描述中不清楚它是可行的还是可取的

  • 排序的向量...取决于您的数据结构元素插入和查找的顺序/重叠,以及您是否负担得起 std::mapstd::vector 的压缩步骤 - 您可以对 std::vector 进行排序由于vector 的连续内存使用情况,因此 (x,y,z) 值的 binary_search 优于 std::map

  • std::unordered_map&lt;key, std::vector&lt;value&gt;&gt;... 预设 1 亿桶容量应该会加快插入速度。这可能比其他选项更慢或更快......索引的内存页面可能比稀疏索引少,但比连续内存上的 binary_search 多,每次查找访问的内存页面最少 # 个,但具有正常哈希即使 x、y、z 坐标仅略有不同,您也会有效地命中随机(但可重复)的哈希桶,因此缓存命中率可能比上述所有其他选项更差。

实际基准始终是调整的最佳方式,最好使用配置文件来确认成本是出于预期原因。

【讨论】:

  • 谢谢,但是如何在地图中插入键值对呢?我将不得不多次为同一个键插入值,并且我不打算先填充向量
  • @user2401047:使用findoperator[]push_back 找到具有给定键的向量。
  • @user2401047: mymap[key].push_back(value)(假设您不需要检查唯一性或对值进行排序)。
  • @Tony D,你还没有听到完整的敲击声,我还需要从这个包含 8000 万个点到数据集中所有点的数据集中找出半径为 r 的所有最近邻居5000万点,我不知道如何为此使用Kd树或八叉树。我需要为他们提供好的教程。这是我必须做的主要事情,我之前解释的问题(这个问题所指的)是次要的。
  • @user2401047:变得棘手 - 什么是最佳或接近将在很大程度上取决于您的数据集的稀疏程度、您必须处理的半径值的分布、您是否有足够的 RAM 可用等.. 我从未听说过 kd 树或八叉树,所以不推荐任何教程。祝你好运!
【解决方案2】:

@TonyD 的回答当然很好,但与

相比有一些权衡
std::multimap<key, value> 

搜索给定键的所有值应该给您相同的O(log N) 复杂度

auto result = my_multimap.equal_range(my_key);

迭代仍然是O(N) 复杂度:

for (auto it = result.first; it != result.second; ++it)
     // bla

然而,在所有现实世界中的std::multimap 实现中,上述迭代是在执行基于节点的指针追逐“连续”值元素,而不是您为@987654327 获得的连续 迭代@ 基于std::map。由于 cache-locality 的原因,这可能很重要。

我从std::vector 解决方案中看到的主要缺点是您承诺将所有值保持在一起,这可能会产生一些开销,具体取决于您复制数据的频率。

multimap 方法可以更轻松地从容器中插入/提取单个值

my_multimap.insert(std::make_pair(some_key, another_value);

auto it = my_map.find(some_key);
if (it != my_map.end()) 
    it->second.push_back(another_value);
else
    my_map.insert(std::make_pair(some_key, another_value));

您可能应该对您的程序进行基准测试,看看哪个容器更方便。

【讨论】:

    猜你喜欢
    • 2013-07-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-12
    • 1970-01-01
    • 1970-01-01
    • 2018-10-28
    相关资源
    最近更新 更多