【问题标题】:Ask for suggestion on a data structure usage征求有关数据结构使用的建议
【发布时间】:2011-04-26 17:07:37
【问题描述】:

对于data1 中的每个元素,我需要弄清楚data2 中的哪些元素与之相关。另外,对于data2 中的每个元素,我需要弄清楚data1 中的哪些元素与之相关。因此,我设置了一个相互数据结构,如下所示:

01  class data1 {
02    // class variables
03    int id;
04    float d1_v1;
05    float d1_v2;
06    map<string, float> m_to_data2; // string is the keyword of data2, float recorded the reference info when data1 and data2 are related.
07  };
08   
09  class data2 {
10    // class variables
11    int d2_v1;
      float d2_v2;
12    list <int> src_id;  // int is the id of data1
13  };
14   
15  map<string, data2 *> map_2;
16  map<int, data1 *> map_1;

然后我解析文件并填充 map_1 和 map_2。我发现:

  1. 设置互链接的两个映射后的总内存使用量:498.7M。

  2. 不设置data2到data1的链接(不填list &lt;int&gt; src_id),内存占用:392.7M。

  3. 不填充map_1,不填充data2中的list &lt;int&gt; src_id,内存使用:182.0M

  4. 不填充map_1,用data1的id填充list &lt;int&gt; src_id,内存使用:289.7M

  5. 没有填充图m_to_data2,内存使用:290.0M

  6. map_1的大小:77737

  7. map_2的大小:1830009

  8. map_1的每个元素的map&lt;string, float&gt;m_to_data2的大小在3 - 17522的范围内

  9. 1-1377范围内map_2的每个元素list &lt;int&gt; src_id的大小

我需要在设置相互链接的映射后减少内存使用量(理想情况下小于 200M,目前为 498M,如上所示)。我试图通过设置一个额外的map &lt;string, int&gt; 将字符串(data2 的关键字)标记为 int,因为 int 需要的内存比字符串少,但它可能没有多大帮助,因为我需要为map &lt;string, int&gt; 提供额外的内存。有什么建议吗?

我们非常感谢您的 cmets/建议。

【问题讨论】:

  • 也许存储指向 data2 的指针而不是 m_to_data2 关键字的字符串?应该节省内存和 CPU 时间。
  • 实际对象有多大(即 ... 中隐藏了什么?) ids 是连续的吗? (密集?稀疏?)您可以做的最简单的事情是将 list 更改为 deque 如果您不需要在中间插入删除(将避免每个对象 2 个指针)或 vector 如果可以最后只使用插入删除进行管理。您可以用哈希映射替换 maps 以减少内存占用,或者如果您可以重用 id 并使它们连续(并且基于 0),那么您可以通过使用 vector(哈希映射对于某些特定情况具有完美的散列)
  • (1) 指针需要与字符串相同的内存,对吧?在这种情况下如何节省内存?
  • ...中没有重要的东西,只有两个 int 变量。这些可能不是减少内存的关键问题。
  • 你真的应该在你的基础上工作,如果你不理解指针和字符串之间的区别,你将无法优化内存占用,不,它们不占用相同的空间.每个字符串都有自己的每个存储字符的副本(可能取决于编译器,它们可能使用写时复制语义)。

标签: c++ data-structures


【解决方案1】:

我会从以下开始:

  • 如果可能(即您有 boost 或 tr1 可用且排序并不重要),请将所有 maps 更改为 unordered_maps。
  • 如果可能,将data2 中的list 更改为vector
  • 有一个从string 映射到unsigned idunordered_map,并在您当前使用字符串的任何地方使用该id。鉴于 m_to_data2 的大小范围为 3-17k,您会重复名称​​很多

【讨论】:

  • 谢谢,巴勃罗。 (1) 将字符串映射到 id 是我想要做的。可能 unsigned int 会是一个更好的主意。 (2) 我可能需要一个有序的地图,因为我需要有效地找到元素。我在以下操作中进行了很多搜索。 (3) 将列表改为向量可以节省内存吗?也许我没有正确理解它们,但我认为 list 需要的内存比 vector 少。
  • list除了存储值之外,还为每个节点至少存储了一个前向和后向指针,而vector只存储了值。
  • unordered_maps 允许快速搜索,甚至比订购的maps 还要快。 unordered_maps 通常使用具有O(1) 查找时间的哈希表实现,maps 通常使用具有O(lg n) 查找时间的红黑树实现。
  • 谢谢,Pablo 和 David,我将阅读 unordered_map 并尝试使用它。
【解决方案2】:

看起来浮动引用变量占用了太多内存,您可以将其更改为无符号整数。

【讨论】:

  • sizeof(float) == sizeof(int)(在最常见的实现中都是 32 位)除非我误解了你的答案,否则将 float 更改为 int 根本没有帮助。
  • 你说得对,对不起,我完全在想别的事/。
  • 感谢您的 cmets。参考需要是浮动的。我的意思是将字符串映射到一个 int,因为 int 需要的内存比 string 少。但这可能没有多大帮助。或者有什么想法可以用更少的内存设置相互链接数据库?
  • 我可能不清楚这个问题,但目前您可以尝试一个多键映射,键是唯一的,从与数据 2 相关的数据 1 映射两个对象。希望这会有所帮助跨度>
  • 谢谢,瓦吉。你是说多地图?
【解决方案3】:

如果我正确理解您的问题,我宁愿使用 std::multimap 而不是 std::map

std::multimap<std::string, int> map2;
std::multimap<int, std::map<std::string, float> > map1;

这将使您的代码更容易理解并进行优化。

【讨论】:

  • 感谢您的建议,Vink。我会研究一下multimap,看看我是否可以使用它。
  • 嗨 Vink,我查看了 multimap 的文档,发现 multimap 可能对我不起作用,因为我有两个用于 data2 的变量,正如您在上面更新的代码中看到的那样。此外,目前,我没有看到使用 multimap 时减少内存使用的一些优势。它只允许地图中存在多个键(我没有看到其他任何键?)。这样一来,它可能会大量重复密钥,并且可能需要更多的内存。
猜你喜欢
  • 2014-09-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-01
  • 2016-05-21
  • 1970-01-01
相关资源
最近更新 更多