为什么尝试访问哈希表中的元素会改变插入行为

时间:2014-09-06 19:56:09

标签: c++ unordered-map

我检查该元素是否已经在哈希表中并且更改了输出 有人可以解释一下原因吗?

#include <iostream>
#include <unordered_map>
using namespace std;
int main(int argc, char *argv[]){
        char c = 'a';
        unordered_map<char,int> myhashmap;
        cout << myhashmap[c] << endl;       // <<--- This line
        myhashmap.insert({c,1});
        cout << myhashmap[c] << endl;
        cout << endl;
}

输出

0
0

但如果删除标记的行,则输出为

1

起初我想,可能是因为检查一个键可能会插入值为零,当我实际插入它时,这将是一个碰撞。所以我检查了unordered_map如何处理碰撞。显然它把它放在桶里。所以我接着这样做,看看我的怀疑是否正确。我所做的就是打印所有水桶和它们的尺寸。

#include <iostream>
#include <unordered_map>
using namespace std;
int main(int argc, char *argv[]){
    char c = 'a';
    unordered_map<char,int> myhashmap;

    for (unsigned i=0; i<myhashmap.bucket_count(); ++i) {
        std::cout << "bucket #" << i << " has " << myhashmap.bucket_size(i) << " elements.\n";
  }
  cout << endl;
  cout << myhashmap[c] << endl;             // Line 1 - check if the key is present
  cout << endl;

  for (unsigned i=0; i<myhashmap.bucket_count(); ++i) {
        std::cout << "bucket #" << i << " has " << myhashmap.bucket_size(i) << " elements.\n";
  }

  cout << endl;
  myhashmap.insert({c,1});                  // Line 2 - Insert into hashTable
  cout << myhashmap[c] << endl;
  cout << endl;

  for (unsigned i=0; i<myhashmap.bucket_count(); ++i) {
        std::cout << "bucket #" << i << " has " << myhashmap.bucket_size(i) << " elements.\n";
  }
}
唉,我的假设是错误的。最初所有桶的大小都为零。当我检查密钥(第1行)时,其中一个桶的大小变为1.但即使在插入(第2行)之后,桶的大小仍为1,但输出为0而不是1.我必须误解一些非常基本的哈希表。如果有人能解释我做错了什么,我将不胜感激

由于

2 个答案:

答案 0 :(得分:2)

  

起初我想,可能是因为检查密钥可能会将其插入零值

这正是发生的事情。您没有正确检查它。以下是执行myhashmap[c]时如何查看插入的内容:

char c = 'a';
unordered_map<char,int> myhashmap;
cout << "Size before: " << myhashmap.size() << endl;
cout << myhashmap[c] << endl;
cout << "Size after: " << myhashmap.size() << endl;\
auto iter = myhashmap.find(c);
cout << "iter is valid: " << (iter != myhashmap.end()) << endl;
cout << "Key is " << iter->first << endl;
cout << "Value is " << iter->second << endl;

该程序产生以下输出:

Size before: 0
0
Size after: 1
iter is valid: 1
Key is a
Value is 0

Demo.

答案 1 :(得分:1)

首先,让我们看看std::unordered_map::operator[]

  

返回对映射到等效于key的键的值的引用,如果此类键尚不存在则执行插入。   如果执行插入,则映射值是值初始化的(默认为类类型构造,否则为零初始化),并返回对它的引用。

因此,在您的第一行{'a',0}中插入了地图。现在打电话给std::unordered_map::insert

  

将元素插入容器中,如果容器尚未包含具有等效键的元素

(强调我的。)因此,如果您在operator[](c)之前致电insert({c,1}),则对insert的调用无效,否则会插入{c,1}