C++ 標準庫中的哈希函數:從std::hash到自定義哈希器

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;而從詳情頁返回列表頁又希望保留滾動位置…