C++笔记:std::hash

cpp 复制代码
#include<functional>
template< class Key >
struct hash; 

std::hash 本质上是一个 模板函数对象(function object)

可以把它理解为一个函数对象,自然它实现了operator()方法。

本文不深究具体原理,只讲一下如何使用std::hash

如何使用

cpp 复制代码
#include <iostream>
#include <functional>

int main()
{
    std::hash<int> hasher;

    size_t h1 = hasher(10);
    size_t h2 = hasher(20);

    std::cout << h1 << std::endl;
    std::cout << h2 << std::endl;
}
bash 复制代码
10155668643424727455
14764355265743743681

返回值类型是std::size_t

标准库的规则

  1. 接收 Key 类型的单个参数
  2. 返回表示参数散列值的 std::size_t 类型。
  3. 调用时不抛出异常。
  4. 对于二个相等的参数 k1k2 , std::hash<Key>()(k1) == std::hash<Key>()(k2) 。
  5. 对于二个相异而不相等的参数 k1k2 , std::hash<Key>()(k1) == std::hash<Key>()(k2) 的概率应非常小,接近 1.0/std::numeric_limits<std::size_t>::max() 。

标准库已经提供了很多类型的哈希实现:

bash 复制代码
//基本类型
int
long
float
double
bool
//指针
T*
//字符串
std::string
std::wstring
std::string_view    //C++20支持
//注意对于C字符串const char *,并不会对所有字符进行哈希,而是仅视为指针

std::hash 在 unordered_*里的作用

无序关联容器 std::unordered_set 、 std::unordered_multiset 、 std::unordered_map 、 std::unordered_multimap 以该模板 std::hash 的特化为默认散列函数。

cpp 复制代码
template <class _Kty, class _Ty, class _Hasher = std::hash<_Kty>, class _Keyeq = std::equal_to<_Kty>
class unordered_map;

如何给自定义的类定义hash?

假设我们自定义了一个类Point

cpp 复制代码
struct Point
{
    int x;
    int y;
};
std::unordered_map<Point, int> mp; // ❌ 编译错误

因为std::hash<Point>不存在

哈希表必须知道:Point -> hash

方法1:特化 std::hash(最常用)

cpp 复制代码
#include <iostream>
#include <functional>
#include<unordered_map>
struct Point {
    int x;
    int y;
};
// std::hash 的自定义特化能注入 namespace std
namespace std
{
    template<>
    struct hash<Point>
    {
        size_t operator()(const Point& p) const
        {
            return std::hash<int>{}(p.x) ^ std::hash<int>{}(p.y);
        }
    };
}
int main()
{
    std::hash<Point> hasher;//可以
    std::unordered_map<Point, int> mp;//可以实例化
    mp.insert(std::make_pair(Point{ 1,2 }, 1));//但插入有问题
    
}

哈希表不仅要 hash,还要判断相等。

cpp 复制代码
#include <iostream>
#include <functional>
#include<unordered_map>
struct Point
{
    int x;
    int y;
    //要加入==操作
    bool operator==(const Point& other) const
    {
        return x == other.x && y == other.y;
    }
};
// std::hash 的自定义特化能注入 namespace std
namespace std
{
    template<>
    struct hash<Point>
    {
        size_t operator()(const Point& p) const
        {
            return std::hash<int>{}(p.x) ^ std::hash<int>{}(p.y);
        }
    };
}
int main()
{
    std::hash<Point> hasher;
    std::unordered_map<Point, int> mp;
    mp.insert(std::make_pair(Point{ 1,2 }, 1));
    
}

方法2:自定义 hash 函数(不用特化)

cpp 复制代码
#include <iostream>
#include <functional>
#include<unordered_map>
struct Point
{
    int x;
    int y;

    bool operator==(const Point& other) const
    {
        return x == other.x && y == other.y;
    }
};
//相当于自己设计hash算法的可调用对象类
struct PointHash
{
    std::size_t operator()(const Point& p) const
    {
        return p.x * 31 + p.y;
    }
};
int main()
{
    //让哈希表用自己的算法
    std::unordered_map<Point, int,PointHash> mp;
    mp.insert(std::make_pair(Point{ 1,2 }, 1));
    
}
相关推荐
灰色小旋风2 小时前
力扣 12 整数转罗马数字 C++
开发语言·c++·leetcode
8Qi82 小时前
环形链表刷题笔记(LeetCode热题100--141、142)
c语言·数据结构·c++·算法·leetcode·链表
Kang.Charles2 小时前
UE4 C++将Json数据写入目标字符串
c++·json·ue4
好的收到1112 小时前
PyTorch深度学习(小土堆)笔记4: PyTorch 训练不再“开盲盒”,TensorBoard 可视化保姆级教程
pytorch·笔记·深度学习
Yupureki2 小时前
《算法竞赛从入门到国奖》算法基础:数据结构-单调队列
c语言·数据结构·c++·算法
搞机械的假程序猿2 小时前
STC32G学习笔记-FreeRTOS for STC32G12K128
笔记·单片机·学习
小指纹2 小时前
每日一题--Tokitsukaze and Colorful Chessboard【二分】
数据结构·c++·算法
柏木乃一2 小时前
Linux线程(6)生产消费者模型
linux·运维·服务器·c++·分布式·线程·生产消费
co_wait2 小时前
【C++ STL】map容器的基本使用
java·c++·rpc