在C++中使用HashMap的最佳方法是什么?

use*_*855 149 c++ hashmap

我知道STL有一个HashMap API,但我找不到任何好的和全面的文档,并提供了很好的例子.

任何好的例子将不胜感激.

max*_*zig 209

标准库包括有序和无序映射(std::mapstd::unordered_map)容器.在有序映射中,元素按键排序,插入和访问在O(log n)中.通常,标准库内部使用红黑树作为有序映射.但这只是一个实现细节.在无序映射中,插入和访问在O(1)中.它只是哈希表的另一个名称.

(有序)的例子std::map:

#include <map>
#include <iostream>
#include <cassert>

int main(int argc, char **argv)
{
  std::map<std::string, int> m;
  m["hello"] = 23;
  // check if key is present
  if (m.find("world") != m.end())
    std::cout << "map contains key world!\n";
  // retrieve
  std::cout << m["hello"] << '\n';
  std::map<std::string, int>::iterator i = m.find("hello");
  assert(i != m.end());
  std::cout << "Key: " << i->first << " Value: " << i->second << '\n';
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出:

23
Key: hello Value: 23

如果您需要在容器中进行订购并且可以使用O(log n)运行时,那么只需使用std::map.

否则,如果你真的需要一个哈希表(O(1)插入/接入),退房std::unordered_map,其中有一个类似的std::mapAPI(例如,在你只需要搜索和替换上面的例子mapunordered_map).

unordered_map容器是在C++ 11标准版本中引入的.因此,根据您的编译器,您必须启用C++ 11功能(例如,使用GCC 4.8时,您必须添加-std=c++11到CXXFLAGS).

甚至在C++ 11发布GCC支持之前unordered_map- 在命名空间中std::tr1.因此,对于旧的GCC编译器,您可以尝试使用它:

#include <tr1/unordered_map>

std::tr1::unordered_map<std::string, int> m;
Run Code Online (Sandbox Code Playgroud)

它也是boost的一部分,即你可以使用相应的boost-header来获得更好的可移植性.

  • @ShameelMohamed,2017年,即在C++ 11之后的6年,应该很难找到一个不提供`unordered_map`的STL.因此,没有理由考虑非标准的[`hash_map`](https://www.sgi.com/tech/stl/hash_map.html). (2认同)

Jer*_*fin 27

A hash_map是标准化目的的较旧的非标准化版本unordered_map(目前作为TR1的一部分提供,将包含在C++ 0x中).顾名思义,它是从不同的std::map主要是无序的-如果,例如,您可以通过地图迭代从begin()end(),你的密钥,以便项目1,但如果你通过一个循环unordered_mapbegin()end(),你在一个项目或多或少的任意顺序.

unordered_map通常预期An 具有恒定的复杂性.也就是说,插入,查找等基本上花费固定的时间量,而不管表中有多少项.对于std::map存储的项目数量具有对数的复杂性 - 这意味着插入或检索项目的时间增长,但随着地图变大,非常缓慢.例如,如果查找100万个项目中的一个需要1微秒,那么您可以预期查找200万个项目中的一个需要大约2微秒,400万个项目中的一个项目需要3微秒,800万个项目中的一个项目需要4微秒物品等

从实际的角度来看,这并非真正的整个故事.本质上,简单的哈希表具有固定的大小.使其适应通用容器的可变大小要求有点不重要.结果,(可能)增长或缩小表格(例如,插入和删除)的操作通常相对较慢.查找不能改变表的大小,通常要快得多.因此,当您进行大量查找和相对较少的插入和删除时,大多数基于散列的表往往处于最佳状态.对于插入大量数据的情况,然后遍历表一次以检索结果(例如,计算文件中唯一单词的数量),可能性std::map一样快,甚至可能更快.

1std::less<T>默认情况下,在创建地图时,第三个模板参数定义了顺序.

  • 我意识到我是在答案发布 9 年后才来的,但是......你有一个文档的链接,其中提到了无序地图可以缩小尺寸这一事实吗?通常,std 集合只会增长。此外,如果您插入大量数据,但事先或多或少知道要插入多少个键,则可以在创建时指定地图的大小,这基本上消除了调整大小成本(因为不会有任何调整成本) 。 (2认同)

Jer*_*ler 23

这是一个更完整,更灵活的示例,不会忽略生成编译错误所必需的包含:

#include <iostream>
#include <unordered_map>

class Hashtable {
    std::unordered_map<const void *, const void *> htmap;

public:
    void put(const void *key, const void *value) {
            htmap[key] = value;
    }

    const void *get(const void *key) {
            return htmap[key];
    }

};

int main() {
    Hashtable ht;
    ht.put("Bob", "Dylan");
    int one = 1;
    ht.put("one", &one);
    std::cout << (char *)ht.get("Bob") << "; " << *(int *)ht.get("one");
}
Run Code Online (Sandbox Code Playgroud)

对于键仍然没有特别有用,除非它们被预定义为指针,因为匹配值不会做!(但是,由于我通常使用字符串作为键,因此在键的声明中将"string"替换为"const void*"应解决此问题.)

  • 我不得不说,此示例在C ++中是非常糟糕的做法。您使用的是强类型语言,并使用`void *`销毁它。对于初学者来说,没有理由包装unordered_map,因为它是标准的一部分并降低了代码的可维护性。接下来,如果坚持将其包装,请使用`templates`。那正是他们的目的。 (3认同)

Cir*_*四事件 5

std::unordered_map在GCC stdlibc ++ 6.4 中使用哈希映射的证据

/sf/answers/250477321/中提到了此问题,但在以下答案中:在C ++中std :: map内包含什么数据结构?我已通过以下方式为GCC stdlibc ++ 6.4实现提供了进一步的证据:

  • GDB一步调试进入类
  • 性能特征分析

这是该答案中描述的性能特征图的预览:

在此处输入图片说明

如何使用自定义类和哈希函数 unordered_map

这个答案很明确:使用自定义类类型作为键的C ++ unordered_map

摘录:平等:

struct Key
{
  std::string first;
  std::string second;
  int         third;

  bool operator==(const Key &other) const
  { return (first == other.first
            && second == other.second
            && third == other.third);
  }
};
Run Code Online (Sandbox Code Playgroud)

哈希函数:

namespace std {

  template <>
  struct hash<Key>
  {
    std::size_t operator()(const Key& k) const
    {
      using std::size_t;
      using std::hash;
      using std::string;

      // Compute individual hash values for first,
      // second and third and combine them using XOR
      // and bit shifting:

      return ((hash<string>()(k.first)
               ^ (hash<string>()(k.second) << 1)) >> 1)
               ^ (hash<int>()(k.third) << 1);
    }
  };

}
Run Code Online (Sandbox Code Playgroud)