如何为自定义类使用C ++ unordered_set?

时间:2016-07-24 16:11:27

标签: c++ unordered-set hash-function

如何在unordered_set中存储班级的对象?我的程序需要经常检查此unordered_set中是否存在对象,如果存在,则对该对象进行一些更新。

我已经在线查看了如何使用unordered_set,但遗憾的是大多数教程都是关于在intstring类型上使用它。但是我如何在课堂上使用它呢?如何定义哈希函数以使以下示例中的node_id成为unordered_set的关键字?

#include <iostream>
#include <unordered_set>

using namespace std;

// How can I define a hash function that makes 'node' use 'node_id' as key?    
struct node
{
    string node_id;
    double value;
    node(string id, double val) : node_id(id), value(val) {}
};

int main()
{
    unordered_set<node> set;
    set.insert(node("1001", 100));
    if(set.find("1001") != set.end()) cout << "1001 found" << endl;
}

5 个答案:

答案 0 :(得分:5)

您可以尝试使用以下哈希函数对象(它非常基本,因此您可能需要对其进行改进以避免太多冲突)。

struct node_hash {
    std::size_t operator()(const node& _node) const {
        return std::hash<std::string>()(_node.node_id);
    }
}
// ...
std::unordered_set<node, node_hash> node_set;

但是,正如其中一条评论指出的那样,最好在这里使用std::unordered_map<std::string, double>

答案 1 :(得分:1)

您需要实现自定义哈希函数(我建议使用Boost库中的函数)来执行此操作。 C ++允许您使用unordered_set保存指向类对象的指针。在大多数情况下,这应该可以解决问题。

答案 2 :(得分:1)

我同意ArchbishopOfBanterbury,对于您的特定用例,std::unordered_map<std::string, double>可能是更好的选择。但是,如果由于某些原因要坚持使用unordered_set,则也可以使用lambda expression而不是定义哈希函数。但是,您还必须提供比较功能(equal)才能使代码正常工作。如果您希望两个node实例具有相同的node_id是相等的,则可以使用以下代码:

auto hash = [](const node& n){ return std::hash<std::string>()(n.node_id); };
auto equal = [](const node& n1, const node& n2){ return n1.node_id == n2.node_id; };
std::unordered_set<node, decltype(hash), decltype(equal)> set(8, hash, equal);

但是,如果要使用std::unordered_set::find(),则不能简单地向该函数提供字符串(例如"1001"),因为它希望将node对象用作参数。不过,以下代码(创建一个临时对象)可以解决问题:

set.insert(node("1001", 100));
if (set.find(node("1001", 0)) != set.end())
    std::cout << "1001 found" << std::endl;

请注意,尽管插入的1001 found的{​​{1}}与指定给value的{​​{1}}的{​​{1}}不同,但输出node却被打印了。 value函数(分别为100和0)。这是因为比较功能node仅在检查相等性时考虑find()

Code on Ideone

答案 3 :(得分:0)

由于这是Google C++ unordered_set of objects在Stack Overflow上获得的最高排名,因此我将发布一个简单但完全说明性且可复制/粘贴的可运行示例:

// UnorderedSetOfObjects.cpp

#include <iostream>
#include <vector>
#include <unordered_set>

struct Point
{
  int x;
  int y;

  Point() { }
  Point(int x, int y)
  {
    this->x = x;
    this->y = y;
  }
  
  bool operator==(const Point& otherPoint) const
  {
    if (this->x == otherPoint.x && this->y == otherPoint.y) return true;
    else return false;
  }

  struct HashFunction
  {
    size_t operator()(const Point& point) const
    {
      size_t xHash = std::hash<int>()(point.x);
      size_t yHash = std::hash<int>()(point.y) << 1;
      return xHash ^ yHash;
    }
  };
};

int main(void)
{
  std::unordered_set<Point, Point::HashFunction> points;

  points.insert(Point(1, 1));
  points.insert(Point(2, 2));
  points.insert(Point(1, 1));   // notice this is a duplicate with the 1st point so it won't change the set

  std::cout << "points: " << "\n";
  for (auto& point : points)
  {
    std::cout << "(" << point.x << ", " << point.y << ")" << "\n";
  }

  return 0;
}

答案 4 :(得分:0)

正如 How to specialize std::hash<Key>::operator() for user-defined type in unordered containers? 中所指出的,另一种选择是引入 == 运算符并将特化注入 std::hash