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));
    
}
相关推荐
南境十里·墨染春水6 分钟前
C++ 笔记 友元(面向对象)
开发语言·c++·笔记
C++ 老炮儿的技术栈40 分钟前
分享一个安全的CString
c语言·c++·windows·git·安全·visual studio
cqbelt1 小时前
Python 并发编程实战学习笔记
笔记·python·学习
桦01 小时前
[C++复习]:STL
开发语言·c++
苏宸啊2 小时前
rbtree封装map和set
c++
·醉挽清风·2 小时前
学习笔记—Linux—信号阻塞&信号捕捉
linux·笔记·学习
Hello_Embed2 小时前
嵌入式上位机开发入门(四):TCP 编程 —— Client 端实现
网络·笔记·网络协议·tcp/ip·嵌入式
汉克老师3 小时前
GESP2025年6月认证C++三级( 第一部分选择题(1-8))
c++·二进制·原码·补码·gesp三级·gesp3级·八进制、
不想写代码的星星3 小时前
C++ 折叠表达式:“我写递归你写折叠,咱俩代码差十年”
c++
Titan20243 小时前
map和set的封装学习笔记
数据结构·c++