【问题标题】:Is there any way to limit the size of an STL Map?有没有办法限制 STL Map 的大小?
【发布时间】:2010-04-26 07:26:16
【问题描述】:

我想在 C++ 中实现某种查找表,作为缓存。它旨在模拟我正在模拟的一个硬件。

键是非整数,所以我猜散列是有序的。我无意发明轮子,所以我打算为此使用std::map(尽管欢迎提出替代方案的建议)。

问题是,有没有办法限制散列的 size 以模拟我的硬件大小有限的事实?我希望哈希的 insert 方法在达到限制时返回错误消息或抛出异常。

如果没有这样的方法,我会在尝试插入之前简单地检查它的大小,但这似乎是一种不雅的方法。

【问题讨论】:

  • 你可以做的是抛出bad_alloc,这可以通过实现你自己的分配器来完成。这就是您所需要的:stackoverflow.com/questions/1591591/…
  • 地图是一棵树,而不是哈希表结构。它将允许查找,但会在 O(log N) 中搜索(与 O(1) 相比,以获得最佳哈希)
  • @David:只要实现满足该类型的 STL 复杂性要求,就可以按照作者的选择来实现映射。最好不要想象给定的 STL 类型以任何特定的方式实现 - 复杂性要求都是可以保证的。
  • @Nick,我知道标准不需要具体的数据结构,但是评论中对时间复杂度的要求成立:地图中的查找操作是标准中的O(log N)。这也是一个事实,所有现有的 STL 实现都在内部使用树来映射映射(因此,即使从理论的角度来看,蕴含 map => tree 不成立,但从实用的角度来看它确实如此)。部分原因是很难提出一个不同的数据结构来满足标准对所有操作的所有要求。
  • @Nick:哈希表要求键是可哈希的;树要求键是有序的。 C++ 标准确实要求 std::map 键是可排序的,但不要求它们是可散列的。此外,std::map 上的迭代必须以该精确排序顺序迭代所有键。因此,我们可以肯定地说,该标准不允许 std::map 成为哈希表。

标签: c++ stl map


【解决方案1】:

首先,map 结构不是hash table,而是平衡二叉树。这会影响查找时间 O(log N) 而不是 O(1) 以获得最佳哈希实现。这可能会或不会影响您的问题(如果实际键和操作的数量很少,它就足够了,但缓存的模拟可能不是最理想的。

您可以做的最简单的解决方案是将实际数据结构封装到一个类中,该类检查每次插入的大小(在所有 STL 实现中,大小查找应该在恒定时间内实现),如果出现以下情况则失败您尝试添加的元素过多。

class cache {
public:
   static const int max_size = 100;
   typedef std::map<key_t, value_t> cache_map_t;
   void add( key_t key, value_t value ) {
      cache_map_t::const_iterator it = m_table.find( key );
      if ( it != m_table.end() && m_table.size() == max_size ) { 
         // handle error, throw exception...
      } else {
         m_table.insert( it, std::make_pair(key,value) );
      }
   }
private:
   cache_map_t m_table;
};
// Don't forget, in just one translation unit:
const int cache::max_size;

【讨论】:

  • 给定 std::map 的实现细节超出了 C++ 规范的范围。不能保证地图就是一棵树。
  • @Nick:是的,但标准中对 std::map 的复杂性要求并没有给实现留下太多选择。我挑战你找到一个不是树的符合标准的 std::map 实现:)
  • 我已经回答了与问题中的评论相同的内容。从标准中提取所有要求并尝试提出不同的实现(即尝试实现一个不断增长的映射,其中插入采用带有哈希的O(log N)),或者,提到一个映射不是平衡树的STL 实现。
  • @Nick:据我所知,只有树或跳过列表才能满足标准对map/set 的约束。无论如何,它不是哈希映射。 (并且一直打算成为一棵树。)
【解决方案2】:

没有办法“自动”限制std::map 的大小,因为“有限的std::map”不再是std::map。

将std::map 包装在您自己的类中,该类仅在插入之前根据常量检查std::map 的大小,并在达到最大大小的情况下执行您想要的任何操作。

【讨论】:

    【解决方案3】:

    如果您正在实现 LRU 缓存或类似的东西,我发现 boost::bimap 非常宝贵。使用一个索引作为主要的“对象 ID”键(如果您有一个简单的对象枚举,它可以是一个高效的矢量视图),另一个索引可以是一个有序的时间戳。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-08-29
      • 1970-01-01
      • 2021-10-04
      • 1970-01-01
      • 1970-01-01
      • 2015-03-23
      • 2012-10-30
      相关资源
      最近更新 更多