高级农民
- 积分
- 2716
- 大米
- 颗
- 鳄梨
- 个
- 水井
- 尺
- 蓝莓
- 颗
- 萝卜
- 根
- 小米
- 粒
- 学分
- 个
- 注册时间
- 2017-6-18
- 最后登录
- 1970-1-1
|
本帖最后由 magicsets 于 2018-4-22 12:54 编辑
因为std::unordered_set的完全定义( http://en.cppreference.com/w/cpp/container/unordered_set )是:- template<
- class Key,
- class Hash = std::hash<Key>,
- class KeyEqual = std::equal_to<Key>,
- class Allocator = std::allocator<Key>
- > class unordered_set;
复制代码 在不显式提供Hash算子的情况下,默认使用std::hash作为哈希函数。
而std::hash只实现了基础类型( http://en.cppreference.com/w/cpp/utility/hash )的特化,例如int、double、std::string之类的 —— 这方面的知识稍微有点复杂。
在不追求极限性能的情况下我们可以自己写一些std::hash对于复合数据结构的特化,例如std::pair、std::tuple和std::vector,参考实现如下:- #include <cstddef>
- #include <iostream>
- #include <tuple>
- #include <type_traits>
- #include <unordered_set>
- #include <utility>
- #include <vector>
- namespace details {
- inline std::size_t CombineHashes(const std::size_t first_hash,
- const std::size_t second_hash) {
- // C++ boost库里的组合hash方法
- // https://stackoverflow.com/questions/2590677/how-do-i-combine-hash-values-in-c0x
- return first_hash
- ^ (second_hash + 0x9e3779b9u + (first_hash << 6) + (first_hash >> 2));
- }
- } // namespace project
- namespace std {
- template <typename FirstT, typename SecondT>
- struct hash<pair<FirstT, SecondT>> {
- size_t operator()(const pair<FirstT, SecondT> &value) const {
- size_t first_hash = hash<FirstT>()(value.first);
- size_t second_hash = hash<SecondT>()(value.second);
- return details::CombineHashes(first_hash, second_hash);
- }
- };
- template <typename ...Ts>
- struct hash<tuple<Ts...>> {
- size_t operator()(const tuple<Ts...> &value) const {
- return computeHash<sizeof...(Ts)>(value);
- }
- template <size_t idx>
- size_t computeHash(const tuple<Ts...> &value,
- typename std::enable_if<idx == 0>::type * = 0) const {
- return 0;
- }
- template <size_t idx>
- size_t computeHash(const tuple<Ts...> &value,
- typename std::enable_if<idx != 0>::type * = 0) const {
- using T = typename tuple_element<idx-1, tuple<Ts...>>::type;
- const auto &entry = std::get<idx-1>(value);
- return details::CombineHashes(hash<T>()(entry),
- computeHash<idx-1>(value));
- }
- };
- template <typename T>
- struct hash<vector<T>> {
- size_t operator()(const vector<T> &value) const {
- size_t hash_value = 0;
- for (const auto &entry : value) {
- hash_value = details::CombineHashes(hash_value, hash<T>()(entry));
- }
- return hash_value;
- }
- };
- } // namespace std
- int main(int argc, char *argv[]) {
- std::unordered_set<std::vector<int>> data;
- data.emplace(std::vector<int>{1, 2, 3});
- data.emplace(std::vector<int>{4, 5});
- data.emplace(std::vector<int>{1, 2, 3});
- std::cout << "# entries = " << data.size() << "\n";
- // 输出
- // 2
- for (const auto &entry : data) {
- for (const auto &value : entry) {
- std::cout << value << " ";
- }
- std::cout << "\n";
- }
- // 输出(顺序不一定):
- // 1 2 3
- // 4 5
- return 0;
- }
复制代码 你可以把上面代码中main函数前面的代码做成一个头文件"hash.h",然后每次include这个头文件就可以使用vector、pair、tuple的任意组合了,比如:- std::unordered_set<std::vector<std::pair<std::vector<std::string>, std::tuple<float, float, float>>>> data;
复制代码 |
|