C++ 标准库中的哈希函数:从 std::hash 到自定义哈希器

1. 引言

在上一篇中,我们介绍了哈希表为什么能够实现 O(1) 查找。
核心秘密在于:哈希函数

在 C++ 标准库中,哈希表容器(如 unordered_mapunordered_set)依赖一个统一的机制:std::hash
那么 std::hash 是什么?它能处理哪些类型?如果我要存储自定义类型,应该怎么写哈希函数呢?
本文将一一揭开这些问题。

2. 什么是 std::hash

std::hash 是 C++ 标准库提供的 函数对象模板。它为常见的基础类型(如 intdoublestring 等)定义了默认哈希函数。

简单理解:

  • std::hash<T> 是一个类模板。

  • 它重载了 operator(),返回一个 size_t 类型的哈希值。

  • 默认可以直接用于 unordered_mapunordered_set

示例代码

#include <iostream>
#include <string>
#include <functional>
using namespace std;int main() {hash<int> hashInt;hash<string> hashStr;cout << "Hash(42) = " << hashInt(42) << endl;cout << "Hash(\"Alice\") = " << hashStr("Alice") << endl;return 0;
}

输出的结果是一个整数(具体值依赖编译器实现),这个整数就是键的哈希值。

3. std::hash 支持哪些类型

标准库中,以下常见类型都有默认实现:

  • 所有基本数值类型:int, long, double, char

  • 指针类型:T*

  • std::stringstd::u16string 等字符串类

因此,对于这些类型,你可以直接使用 unordered_map

#include <unordered_map>
#include <string>
using namespace std;int main() {unordered_map<string, int> score = {{"Alice", 90},{"Bob", 85}};return 0;
}

无需额外定义哈希函数。

4. 为什么需要自定义哈希函数

如果你要存储 自定义类型(例如坐标点、复数、pair 等),标准库并不知道如何为其生成哈希值。
这时就需要 自己提供哈希函数

5. 自定义哈希函数的方法

方法一:自定义函数对象

#include <iostream>
#include <unordered_set>
using namespace std;struct Point {int x, y;bool operator==(const Point& other) const {return x == other.x && y == other.y;}
};struct PointHash {size_t operator()(const Point& p) const {return hash<int>()(p.x) ^ (hash<int>()(p.y) << 1);}
};int main() {unordered_set<Point, PointHash> points;points.insert({1, 2});points.insert({3, 4});cout << "size = " << points.size() << endl;return 0;
}

这里:

  • operator== 用于判断两个对象是否相等。

  • PointHash 提供哈希值。

  • 注意用位运算(如 ^<<)来混合不同字段,减少冲突。

方法二:使用 lambda(C++14 起)

#include <unordered_map>
#include <string>
#include <functional>
#include <utility>
using namespace std;int main() {auto pair_hash = [](const pair<int,int>& p) {return hash<int>()(p.first) ^ (hash<int>()(p.second) << 1);};unordered_map<pair<int,int>, string, decltype(pair_hash)> mp(10, pair_hash);mp[{1,2}] = "坐标(1,2)";return 0;
}

这种方式更灵活,但语法稍微复杂,需要 decltype(pair_hash) 指定哈希类型。

方法三:偏特化 std::hash

C++ 允许为自定义类型对 std::hash 模板进行偏特化:

#include <unordered_set>
#include <string>
using namespace std;struct Student {string name;int id;bool operator==(const Student& other) const {return name == other.name && id == other.id;}
};namespace std {template<>struct hash<Student> {size_t operator()(const Student& s) const {return hash<string>()(s.name) ^ (hash<int>()(s.id) << 1);}};
}int main() {unordered_set<Student> students;students.insert({"Alice", 1001});students.insert({"Bob", 1002});return 0;
}

这种写法简洁,直接扩展 std::hash,但要小心命名空间污染。

6. 哈希函数设计小技巧

  1. 避免简单相加:如 x + y 容易冲突。

  2. 使用移位和异或(hash1 ^ (hash2 << 1)) 是常见组合方式。

  3. 考虑质数:在复杂结构中,可用质数混合提高分布性。

  4. 保持快速:哈希函数需要高效,否则会拖慢整体性能。

7. 小结

  • std::hash 是 C++ 哈希表的默认入口,支持常见基础类型。

  • 对于自定义类型,需要提供哈希函数,可以通过函数对象、lambda 或偏特化实现。

  • 好的哈希函数应当 分布均匀 + 高效计算,否则会导致严重冲突,影响性能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/96653.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/96653.shtml
英文地址,请注明出处:http://en.pswp.cn/pingmian/96653.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在图形 / 游戏开发中,为何 Pixels Per Unit(PPU)数值越小,物体在屏幕上显示的尺寸越大?

1. 什么是 PPU&#xff1f; PPU&#xff08;Pixels Per Unit&#xff09;指的是 多少像素对应游戏世界中的一个单位&#xff08;Unit&#xff09;。 在 Unity 等游戏引擎中&#xff0c;1 Unit 通常被视为世界空间的基本长度&#xff0c;比如 1 米。2. PPU 与物体大小的关系PPU …

【ZYNQ开发篇】Petalinux和电脑端的静态ip地址配置

使用Petalinux工具为ZYNQ板卡搭建嵌入式Linux操作系统&#xff0c;成功搭建后&#xff0c;用户通常会使用客户端软件对ZYNQ板卡上的Linux系统进行访问&#xff0c;软件需要知道ZYNQ板卡的ip地址才能进行访问&#xff0c;如果ip地址是动态变化的&#xff0c;软件每次访问都要重新…

AVL树知识总结

AVL树概念性质一颗AVL树或是空树&#xff0c;或者具有一下性质的二叉搜索树&#xff1a;左右都是AVL树&#xff0c;左右子树高度差的绝对值不超过1AVL树有n个结果&#xff0c;高度保持在O&#xff08;logN&#xff09; 搜索时间复杂度O(logN&#xff09;模拟实现插入定义&#…

返利app的跨域问题解决方案:CORS与反向代理在前后端分离架构中的应用

返利app的跨域问题解决方案&#xff1a;CORS与反向代理在前后端分离架构中的应用 大家好&#xff0c;我是阿可&#xff0c;微赚淘客系统及省赚客APP创始人&#xff0c;是个冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01; 在返利APP的前后端分离架构中&#xff0c;跨…

【dl】python基础 深度学习中需要用到的python基础

直接在jupyter写笔记然后导出md格式真的太好用了本文笔记来自小破站视频BV1K14y1c75ePython 基础 1. 变量 1.1 三种基本变量类型 # 字符串 str str_v "123"# 数字 int或float num_v 11 float_v 12.0# 布尔型 bool bool_v True1.1.1 字符串 f字符串&#xff1a;在…

Vue FullPage.js 完整使用指南:Vue 3 官方全屏滚动解决方案

概述 vue-fullpage.js 是 FullPage.js 的官方 Vue.js 3 包装器&#xff0c;为 Vue 3 应用提供了强大的全屏滚动功能。该插件基于成熟的 FullPage.js 库&#xff0c;支持多种滚动效果和丰富的配置选项&#xff0c;特别适用于企业级数据大屏、产品展示、单页应用等场景。 官方信…

软件工程实践一:Git 使用教程(含分支与 Gitee)

文章目录目标一、快速上手1. Windows 安装 Git2. 初始化 / 克隆二、核心概念速览三、常用命令清单1) 查看状态与差异2) 添加与提交3) 历史与回溯4) 撤销与恢复&#xff08;Git 2.23 推荐新命令&#xff09;5) 忽略文件四、分支与合并&#xff08;Branch & Merge&#xff09…

css`min()` 、`max()`、 `clamp()`

min() 用来计算多个数值中最小的那个&#xff0c;非常适合做自适应。 width: min(50vw, 500px) 50vw 表示 视口宽度的 50% 500px 表示 500px min(50vw, 500px) 表示会取两者中 最小的那个 作为最终的宽度&#xff0c;。 使用场景 限制某个元素宽度不超过某个值&#xff1b; 响…

【WRF-VPRM 预处理器】HEG 安装(服务器)-MRT工具替代

目录 HEG 安装 验证 HEG 安装与否 设置环境变量(建议) 命令行接口(Command Line Interface) hegtool 工具 hegtool 用法 Header File 格式 功能1:`gdtif` 工具 – MISR 数据处理 `gdtif` 使用方式 参数文件格式(Parameter File Format) 功能2:`resample` 工具 – 重采样…

PyTorch 神经网络

神经网络是一种模仿人脑神经元链接的计算模型&#xff0c; 由多层节点组成&#xff0c; 用于学习数据之间的复杂模式和关系。神经网络通过调整神经元之间的连接权重来优化预测结果&#xff0c;这个过程可以涉及到向前传播&#xff0c;损失计算&#xff0c;反向传播和参数更新。…

详细解析苹果iOS应用上架到App Store的完整步骤与指南

&#x1f4f1;苹果商店上架全流程详解 &#x1f469;‍&#x1f4bb;想要将你的App上架到苹果商店&#xff1f;跟随这份指南&#xff0c;一步步操作吧&#xff01; 1️⃣ 申请开发者账号&#xff1a;访问苹果开发者网站&#xff0c;注册并支付99美元年费&#xff0c;获取开发者…

三维GIS开发实战!Cesium + CZML 实现火箭飞行与分离的 3D 动态模拟

CZML是一种基于JSON的数据格式&#xff0c;专门用于在Cesium中描述3D场景和时间动态数据。本文将详细介绍了CZML的特点&#xff08;JSON格式、时间动态性、层次结构等&#xff09;和基本组件&#xff0c;并给出了一个火箭发射的实例。通过搭建Cesium开发环境&#xff08;使用vi…

Spring Boot 深入剖析:BootstrapRegistry 与 BeanDefinitionRegistry 的对比

在 Spring Boot 的启动过程中&#xff0c;BootstrapRegistry 和 BeanDefinitionRegistry 是两个名为“Registry”却扮演着截然不同角色的核心接口。理解它们的差异是深入掌握 Spring Boot 启动机制和进行高级定制开发的关键。BootstrapRegistry public static ConfigurableAppl…

贪心算法应用:速率单调调度(RMS)问题详解

Java中的贪心算法应用&#xff1a;速率单调调度(RMS)问题详解 1. 速率单调调度(RMS)概述 速率单调调度(Rate Monotonic Scheduling, RMS)是一种广泛应用于实时系统中的静态优先级调度算法&#xff0c;属于贪心算法在任务调度领域的经典应用。 1.1 基本概念 RMS基于以下原则&…

Cesium4--地形(OSGB到3DTiles)

1 OSBG OSGB&#xff08;OpenSceneGraph Binary&#xff09;是基于 OpenSceneGraph&#xff08;OSG&#xff09; 三维渲染引擎的二进制三维场景数据格式&#xff0c;广泛用于存储和传输倾斜摄影测量、BIM、点云等大规模三维模型&#xff0c;尤其在国产地理信息与智慧城市项目中…

多语言共享贩卖机投资理财共享售卖机投资理财系统

多语言共享贩卖机投资理财/共享售卖机分红/充电宝/充电桩投资理财系统 采用thinkphp内核开发&#xff0c;支持注册赠金、多级分销&#xff0c;功能很基础 修复后台用户列表管理 可自定义理财商品 多种语言还可以添加任意语言 源码开源 多级分销 注册赠金等

[Windows] PDF 专业压缩工具 v3.0

[Windows] PDF 专业压缩工具 v3.0 链接&#xff1a;https://pan.xunlei.com/s/VOZwtC_5lCF-UF6gkoHuxWMoA1?pwdchg8# PDF 压缩工具 3.0 新版功能特点 - 不受页数限制&#xff01; 一、核心压缩功能 1.多模式智能压缩 支持 4 种压缩模式&#xff1a;平衡模式&#xff08…

SHEIN 希音 2026 校招 内推 查进度

SHEIN 希音 2026 校招 内推 查进度 &#x1f3e2;公司名称&#xff1a;SHEIN 希音 &#x1f4bb;招聘岗位&#xff1a;前端、后端、测试、产品、安全、运维、APP 研发、数据分析、设计师、买手、企划、招商、管培生 &#x1f31f;内推码&#xff1a;NTA2SdK &#x1f4b0;福利待…

ARM (6) - I.MX6ULL 汇编点灯迁移至 C 语言 + SDK 移植与 BSP 工程搭建

回顾一、核心关键字&#xff1a;volatile1.1 作用告诉编译器&#xff1a;被修饰的变量会被 “意外修改”&#xff08;如硬件寄存器的值可能被外设自动更新&#xff09;&#xff0c;禁止编译器对该变量进行优化&#xff08;如缓存到寄存器、删除未显式修改的代码&#xff09;。本…

Vue中使用keep-alive实现页面前进刷新、后退缓存的完整方案

Vue中使用keep-alive实现页面前进刷新、后退缓存的完整方案 在Vue单页应用中&#xff0c;路由切换时组件默认会经历完整的销毁-重建流程&#xff0c;这会导致两个典型问题&#xff1a;从搜索页跳转到列表页需要重新加载数据&#xff0c;而从详情页返回列表页又希望保留滚动位置…