0x10基础数据结构-(5)-Hash

如果题目已知了要统计的数据的范围,并且不离散不太大,可以直接用数组统计,不用解决Hash冲突,更快

Hash 还有这样的初始化方法,很优雅,像python的Counters

https://leetcode.cn/problems/make-array-zero-by-subtracting-equal-amounts/

unordered_set s(nums.begin(), nums.end());

复合类型作为hash的Key

std::pair 是标准模板库(STL)中定义的模板类,用于组合两个元素。

std::tuple 是标准模板库(STL)中定义的模板类,用于组合三个及以上元素。

struct结构体或class类是用户自定义类型,可以由多个数据成员组成,每个成员可以是不同类型。

这些复合类型不能直接作为Hash Table的key来使用。

pair

std::pair 表示一个有序的、固定大小的、两个值的元组,每个值可以有不同的类型。

#include <unordered_map>
#include <functional>  // std:hash

struct PairHash {
    template<typename T1, typename T2>
    std::size_t operator()(const std::pair<T1, T2>& pair) const {
        return std::hash<T1>{}(pair.first) ^ 
               std::hash<T2>{}(pair.second);
    }
};

std::unordered_map<std::pair<int, int>, double, PairHash> myMap;

tuple

std::tuple 表示一个有序的、固定大小的、多个值的元组,每个值可以有不同的类型。

#include <unordered_map>
#include <functional>  // std:hash

struct TupleHash {
    template<typename... T>
    std::size_t operator()(const std::tuple<T...>& tup) const {
        return std::hash<std::string>{}(std::get<0>(tup)) ^
               std::hash<std::string>{}(std::get<1>(tup)) ^
               std::hash<std::string>{}(std::get<2>(tup));
    }
};

std::unordered_map<std::tuple<int, int, std::string>, double, TupleHash> myMap;

struct / class

结构体作为hash表的key,除了要像std::pairstd:tuple那样实现hash函数,还要实现相等性比较函数:

#include <unordered_map>
#include <functional>  // std:hash

struct Person {
    std::string name;
    int age;
    std::string address;
};

// 组合哈希函数
struct PersonHash {
    std::size_t operator()(const Person& p) const {
        std::size_t nameHash = std::hash<std::string>{}(p.name);
        std::size_t ageHash = std::hash<int>{}(p.age);
        std::size_t addressHash = std::hash<std::string>{}(p.address);
        return nameHash ^ (ageHash << 1) ^ (addressHash << 2);
    }
};
// 相等性比较函数
struct PersonEqual {
    bool operator()(const Person& p1, const Person& p2) const {
        return p1.name == p2.name && p1.age == p2.age && p1.address == p2.address;
    }
};

std::unordered_map<Person, std::string, PersonHash, PersonEqual> peopleMap;

也可以用另一种函数:

// 旋转哈希函数
struct PersonHash {
    std::size_t operator()(const Person& p) const {
        std::size_t nameHash = std::hash<std::string>{}(p.name);
        std::size_t ageHash = std::hash<int>{}(p.age);
        std::size_t addressHash = std::hash<std::string>{}(p.address);
        const std::size_t rotateBits = sizeof(std::size_t) / 2; // 旋转的位数,这里假设是std::size_t的一半
        nameHash = (nameHash << rotateBits) | (nameHash >> (sizeof(nameHash) * 8 - rotateBits));
        ageHash = (ageHash << rotateBits) | (ageHash >> (sizeof(ageHash) * 8 - rotateBits));
        addressHash = (addressHash << rotateBits) | (addressHash >> (sizeof(addressHash) * 8 - rotateBits));
        return nameHash ^ ageHash ^ addressHash;
    }
};