【问题标题】:unordered_map insertion crawls to a haltunordered_map 插入爬行停止
【发布时间】:2011-12-23 05:57:41
【问题描述】:

基本上,我有一个 unordered_map 并尝试向其中添加成对的集合......其中大约 500,000 个。我注意到,当我添加对时,插入速度越来越慢,直到它最终完全停止。关于为什么会这样或如何解决这个问题的任何想法?

地图定义:

std::tr1::unordered_map<std::pair<int, int>, int, pairHash> x_map ;

哈希函数 - 请注意,对于我的情况,我不必担心 pair.first==pair.second,所以我相信这个哈希函数应该足够了,如果错了,请纠正我:

class pairHash
        {
        public:
            size_t operator()(const std::pair<int, int> & v) const
            {
                return v.first ^ v.second ;
            }
        } ;

向 unordered_map 添加值的方法...尝试添加大约 200,000-500,000 对:

initialize_map( EndPoint**& arr, std::tr1::unordered_map<std::pair<int, int>, int, pairHash> &my_map, int size )
{
    for( int i = 0 ; i < size ; i++ )   // add initial overlapping pairs
    {
        if( i % 100 == 0 )
            std::cout << "checking particle: " << i << " maxsize: " << my_map.max_size() << std::endl ;
        int j = 1 ;
        while( arr[i]->isMin && i+j < size &&    // while ys is a min, and not end of array
              arr[i]->v_id != arr[i+j]->v_id )      // anything between min and max is a possible collision
        {
            if( !arr[i]->isEdge || !arr[i+j]->isEdge )
            {
                my_map[std::make_pair( std::min( arr[i]->v_id, arr[i+j]->v_id ),
                        std::max( arr[i]->v_id, arr[i+j]->v_id ) )] = 1 ;
            }

            j++ ;
        }
    }
}

编辑: 我实际上增加了接近 50,000,000 对...刚刚进行了测试...

EDIT2:

冻结前的示例输出,其中 count 是映射中的条目数。我相信它正在尝试重新绘制地图,但不确定为什么它没有这样做并冻结计算机:

检查粒子:87500 计数:35430415 负载系数:0.988477

检查粒子:87600 计数:35470808 负载系数:0.989652

检查粒子:87700 计数:35511049 负载系数:0.990818

检查粒子:87800 计数:35555974 负载系数:0.992073

检查粒子:87900 计数:35595646 负载系数:0.993163

检查粒子:88000 计数:35642165 负载系数:0.994427

检查粒子:88100 计数:35679608 负载系数:0.995434

检查粒子:88200 计数:35721223 负载系数:0.996563

检查粒子:88300 计数:35760313 负载系数:0.997616

检查粒子:88400 计数:35799621 负载系数:0.9987

检查粒子:88500 计数:35833445 负载系数:0.999649

【问题讨论】:

    标签: c++ hash hashmap unordered-map


    【解决方案1】:

    尝试查看 unordered_map::load_factor()。理想情况下,此调用的结果应

    【讨论】:

      【解决方案2】:

      您是否尝试过使用reserve() 为您的所有配对预先分配足够的存储桶?添加这么多对可能会触发许多调整大小(和重新散列)。

      接下来我要检查的是您的哈希函数。它看起来有点可疑,如果你遇到很多哈希冲突,你会得到一堆溢出桶,这会减慢每个插入的查找速度——在这种情况下,你最好使用std::map。您可以修改代码以存储每对的哈希值,然后检查您生成的唯一哈希值的数量。

      【讨论】:

      • tr1::unordered_map 似乎没有reserve() 函数...你的意思是rehash() 吗?看起来这两个功能可能类似于......
      【解决方案3】:

      最好坚持使用 Boost hash_combine 解决方案以获得更好的哈希函数:

      template <class T>
      inline void hash_combine(std::size_t & seed, const T & v)
      {
        std::hash<T> hasher;
        seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
      }
      
      namespace std
      {
        template<typename S, typename T> struct hash< std::pair<S, T> >
        {
          inline std::size_t operator()(const std::pair<S, T> & v) const
          {
            std::size_t seed = 0;
            hash_combine(seed, v.first);
            hash_combine(seed, v.second);
            return seed;
          }
        };
      }
      

      【讨论】:

      • 添加该专业是否合法?标准库不是为pairs 提供hash 吗?
      • @k-ballo - 不,标准库不包含对的散列......遗憾的是:)
      • Kerrek SB - 假设我无法使用 boost 库,你会怎么做呢?
      • @ElfsЯUs:你什么意思?没有库依赖;我发布了完整的代码!什么不清楚?
      • 啊,我的错,是的,你是对的。但是,即使将您的实现用于散列函数,它也会冻结。一旦负载因子达到 0.999,它似乎正在重新散列表格,然后崩溃。关于如何防止这种情况的任何想法? (在冻结之前查看编辑示例输出。)
      猜你喜欢
      • 2023-03-05
      • 1970-01-01
      • 2015-08-01
      • 1970-01-01
      • 2014-07-03
      • 1970-01-01
      • 1970-01-01
      • 2013-05-10
      • 1970-01-01
      相关资源
      最近更新 更多