自定义unordered_map、unordered_set的hash function、compare function

1.问题

C++ STL容器类unordered_map、unordered_set使用起来非常方便,但当向容器中添加自定义类型的元素时,需提供自定义的hash function、compare function,原因:C++ STL只提供了基本类型(如int、string等)的hash function、compare function,其中,自定义hash function用于计算自定义类型对象的hash value,但由于hash function存在碰撞现象,所以自定义compare function用于精准地比较两个自定义类型对象是否相同

unordered_map、unordered_set实现均基于哈希表,所以外部接口相似,这里以unordered_set举例,本博客中的自定义类型Person如下所示:

struct Person {
  string name_;
  int age_;
  Person(string name, int age) {
    name_ = name;
    age_ = age;
  }
};

2.指明hash function的方式

1)将自定义hash function注入到std空间中,这种方式会自动注入unordered_set<Person>中,不用在声明使用unodered_set时再次指明

namespace std {
  template <>
  struct hash<Person> {
    size_t operator()(const Person& person) const {
      size_t res = 17;
      res = res * 31 + hash<string>()(person.name_);
      res = res * 31 + hash<int>()(person.age_);
      return res;
    }
  };  
};

2)将自定义hash function放到一个单独的struct(或class)中,需要在unodered_set中指明承载hash function的struct(或class)

struct PersonHasher1 {
  size_t operator()(const Person& person) const {
    size_t res = 17;
    res = res * 31 + hash<string>()(person.name_);
    res = res * 31 + hash<int>()(person.age_);
    return res;
  }
};

class PersonHasher2 {
public:
  size_t operator()(const Person& person) const {
    size_t res = 17;
    res = res * 31 + hash<string>()(person.name_);
    res = res * 31 + hash<int>()(person.age_);
    return res;
  }
};

3.指明compare function的方式

1)在Person结构体中添加重载运算符operator==

struct Person {
  string name_;
  int age_;
  Person(string name, int age) {
    name_ = name;
    age_ = age;
  }
  bool operator==(const Person& other) const {
    return (name_ == other.name_) && (age_ == other.age_);
  }
};

2)将自定义compare function放到一个单独的struct(或class)中,需要在unodered_set中指明承载compare function的struct(或class)

struct PersonEqual1 {
  bool operator()(const Person& person1, const Person& person2) const {
    return (person1.name_ == person2.name_) && (person1.age_ == person2.age_);
  }
};

class PersonEqual2 {
public:
  bool operator()(const Person& person1, const Person& person2) const {
    return (person1.name_ == person2.name_) && (person1.age_ == person2.age_);
  }
};

4.完整的示例程序

#include <iostream>
#include <unordered_set>

using namespace std;

struct Person {
  string name_;
  int age_;
  Person(string name, int age) {
    name_ = name;
    age_ = age;
  }
  bool operator==(const Person& other) const {
    return (name_ == other.name_) && (age_ == other.age_);
  }
};

namespace std {
  template <>
  struct hash<Person> {
    size_t operator()(const Person& person) const {
      size_t res = 17;
      res = res * 31 + hash<string>()(person.name_);
      res = res * 31 + hash<int>()(person.age_);
      return res;
    }
  };  
};

struct PersonHasher1 {
  size_t operator()(const Person& person) const {
    size_t res = 17;
    res = res * 31 + hash<string>()(person.name_);
    res = res * 31 + hash<int>()(person.age_);
    return res;
  }
};

class PersonHasher2 {
public:
  size_t operator()(const Person& person) const {
    size_t res = 17;
    res = res * 31 + hash<string>()(person.name_);
    res = res * 31 + hash<int>()(person.age_);
    return res;
  }
};

struct PersonEqual1 {
  bool operator()(const Person& person1, const Person& person2) const {
    return (person1.name_ == person2.name_) && (person1.age_ == person2.age_);
  }
};

class PersonEqual2 {
public:
  bool operator()(const Person& person1, const Person& person2) const {
    return (person1.name_ == person2.name_) && (person1.age_ == person2.age_);
  }
};

int main() {
  // unordered_set<Person, PersonHasher2, PersonEqual2> persons;
  unordered_set<Person> persons;
  Person person("zhangsan", 11);
  persons.emplace(person);
  for(auto item : persons) {
    cout << item.name_ << "    " << item.age_ << endl;
  }

  return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值