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. 对于二个相等的参数 k1 与 k2 , std::hash<Key>()(k1) == std::hash<Key>()(k2) 。
  5. 对于二个相异而不相等的参数 k1 与 k2 , 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));
    
}
相关推荐
小成202303202652 小时前
C++~07补充
开发语言·c++
hold?fish:palm2 小时前
40 二叉树的直径
c++·leetcode
解决小子3 小时前
【虚幻引擎】【C++】【GAS框架】构建角色基类、属性集、数值钳制
c++·笔记·游戏引擎·虚幻·gas·能力系统
破芽4 小时前
learn-claude-code-s05-s11-学习笔记
笔记·学习
lunar_coder4 小时前
【C++】如何解决智能指针的析构函数,如何实现shared_ptr的引用计数以及解决shared_ptr的循环引用
c++·1024程序员节
白白白小纯5 小时前
C++进阶.多态
c++
程序猿乐锅5 小时前
【从0-1学习Python | 第七篇】Python 面向对象基础
开发语言·笔记·后端·python·学习·1024程序员节
fish_zzzz6 小时前
笔记--浅谈内存,存储空间,BIOS芯片,显卡GPU、VRAM(1)
笔记·1024程序员节
凯瑟琳.奥古斯特6 小时前
力扣1016高效解法:剪枝优化技巧
开发语言·c++·算法·leetcode·职场和发展
ACP广源盛139246256736 小时前
PCIe Gen3 交换芯片选型笔记:多路扩展方案 IX7024@ACP 评估
笔记·硬件架构·pcie·国产芯片