【C++】哈希表實現

1. 哈希概念

哈希(hash)又稱散列,是?種組織數據的方式。從譯名來看,有散亂排列的意思。本質就是通過哈希 函數把關鍵字Key跟存儲位置建立一個映射關系,查找時通過這個哈希函數計算出Key存儲的位置,進行快速查找

1.1 直接定址法

當關鍵字的范圍較集中時,直接定址法就是簡單高效的方法,如?組關鍵字都在[0,99]之間, 那么開一個100個數的數組,每個關鍵字的值直接就是存儲位置的下標。再如一組關鍵字值都在 [a,z]的小寫字母,那么開一個26個數的數組,每個關鍵字acsii碼-a 的ascii碼就是存儲位置的下標。 也就是說直接定址法本質就是用關鍵字計算出一個絕對位置或者相對位置

1.2 哈希沖突

兩個不同的key可能會映射到同一個位置去,這種問題叫做哈希沖突, 或者哈希碰撞

1.3 負載因子

?假設哈希表中已經映射存儲了N個值,哈希表的大小為M,那么負載因子=N/M ,負載因子有些地方也翻譯為載荷因子/裝載因子等,負載因子越大,哈希沖突的概率越高,空間利用率越高;負載因子越小,哈希沖突的概率越低,空間利用率越低

1.4?哈希函數

一個好的哈希函數應該讓N個關鍵字被等概率的均勻的散列分布到哈希表的M個空間中,但是實際中卻很難做到,盡量往這個方向去考量設計

除法散列法/除留余數法

  • 假設哈希表的大小為M,那么通過key除以M的余數作為映射位置的下標,也就是哈希函數為:h(key)=key%M
  • 當使用除法散列法時,要盡量避免M為某些值,如2的冪,10的冪等
  • 如果是2的冪,那么key % 2^x?本質相當于保留key的后X位,那么后x位相同的值,計算出的哈希值都是?樣的,就沖突了。如果是10的冪 ,保留的都是 10進值的后x位
  • 當使用除法散列法時,建議M取不太接近2的整數次冪的一個質數(素數)

1.5?處理哈希沖突

主要有兩種兩種方法,開放定址法和鏈地址法

1.5.1 開放定址法

在開放定址法中所有的元素都放到哈希表里,當一個關鍵字key用哈希函數計算出的位置沖突了,則按照某種規則找到一個沒有存儲數據的位置進行存儲,開放定址法中負載因子一定是小于的。有三種:線性探測、?次探測、雙重探測

1)線性探測
  • 從發生沖突的位置開始,依次線性向后探測,直到尋找到下一個沒有存儲數據的位置為止,如果走到哈希表尾,則回繞到哈希表頭的位置
  • ,hash0位置沖突了,則線性探測公式為: ,因為負載因子小于1, 則最多探測M-1次,一定能找到一個存儲key的位置
  • 線性探測的比較簡單且容易實現,線性探測的問題假設,hash0位置連續沖突,hash0,hash1, hash2位置已經存儲數據了,后續映射到hash0,hash1,hash2,hash3的值都會爭奪hash3位 置,這種現象叫做群集/堆積。二次探測可以一定程度改善這個問題

2)二次探測
  • 從發生沖突的位置開始,依次左右按二次方跳躍式探測,直到尋找到下一個沒有存儲數據的位置為 為,如果走到哈希表尾,則回繞到哈希表頭的位置;如果往左走到哈希表頭,則回繞到哈希表尾的位置
  • ,hash0位置沖突了,則二次探測公式為:
  • 二次探測當hashi = (hash0 ? i )%M 時,當hashi<0時,需要hashi+=M

1.5.2 開放定址法代碼實現

哈希表結構
enum State
{EXIST,EMPTY,DELETE
};template<class K, class V>
struct HashData
{pair<K, V> _kv;State _state = EMPTY;
};template<class K, class V>
class HashTable
{
private:vector<HashData<K, V>> _tables;size_t _n = 0; // 表中存儲數據個數 
};
擴容

哈希表負載因子控制在0.7,當負載因子到0.7以后就需要擴容了,給了一個近似2倍的質數表,每次去質數表獲取擴容后的大小

inline unsigned long __stl_next_prime(unsigned long n)
{// Note: assumes long is at least 32 bits.static const int __stl_num_primes = 28;static const unsigned long __stl_prime_list[__stl_num_primes] ={53, 97, 193, 389, 769,1543, 3079, 6151, 12289, 24593,49157, 98317, 196613, 393241, 786433,1572869, 3145739, 6291469, 12582917, 25165843,50331653, 100663319, 201326611, 402653189, 805306457,1610612741, 3221225473, 4294967291};const unsigned long* first = __stl_prime_list;const unsigned long* last = __stl_prime_list + __stl_num_primes;const unsigned long* pos = lower_bound(first, last, n);return pos == last ? *(last - 1) : *pos;
}
key不能取模的問題
  • 當key是string/Date等類型時,key不能取模,那么需要給HashTable增加一個仿函數,這個仿函數?持把key轉換成一個可以取模的整形
  • 自己實現一個仿函數傳給這個參數,讓不同的key轉換出的整形值不同
  • string 做哈希表的key很常見,可以考慮把string特化一下
template<class K>
class HashFunc
{
public:size_t operator()(const K& key){return (size_t)key;}
};template<>
class HashFunc<string>
{
public:// 字符串轉換成整形,可以把字符ascii碼相加即可 // 但是直接相加的話,類似"abcd"和"bcad"這樣的字符串計算出是相同的 // 這?我們使?BKDR哈希的思路,?上次的計算結果去乘以一個質數,這個質數一般去31, 131
等效果會?較好size_t operator()(const string& key){size_t hash = 0;for (auto ch : key){hash += ch;hash *= 131;}return hash;}
};
template<class K, class V, class Hash = HashFunc<K>>
class HashTable
{
public:
private:vector<HashData<K, V>> _tables;size_t _n = 0; // 表中存儲數據個數 
};
完整代碼實現

開放地址法

1.5.3 鏈地址法

開放定址法中所有的元素都放到哈希表,鏈地址法中所有的數據不再直接存儲在哈希表中,哈希表 中存儲一個指針,沒有數據映射這個位置時,這個指針為空,有多個數據映射到這個位置時,把這些沖突的數據鏈接成一個鏈表,掛在哈希表這個位置下面,鏈地址法也叫做拉鏈法或者哈希桶

擴容

開放定址法負載因子必須小于1,鏈地址法的負載因子就沒有限制了,可以大于1

這里大于1就擴容

插入邏輯

鏈地址法代碼實現

實現代碼

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/95880.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/95880.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/95880.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

ai 玩游戲 llm玩街霸 大模型玩街霸 (3)

1. 開源代碼地址&#xff1a; https://github.com/OpenGenerativeAI/llm-colosseum 2. 架構&#xff1a; 3. 圖片&#xff1a; 4. 感覺還是下面的步驟&#xff1a; a. 實時理解游戲當前環境&#xff0c;英雄角色&#xff0c;英雄狀態 b. 根據當前狀態感知&#xff0c;生成英雄…

2025年滲透測試面試題總結-59(題目+回答)

安全領域各種資源&#xff0c;學習文檔&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各種好玩的項目及好用的工具&#xff0c;歡迎關注。 目錄 一、SQL注入全解 二、XSS與文件漏洞 三、服務端漏洞專題 四、職業經驗與能力評估 1、注入攻擊原理是什么…

GPT系列--類GPT2源碼剖析

無需多言&#xff0c;大家應該都用過了&#xff0c;如今都更新到GPT-5了。1. GPT-1回到2018年的NLP&#xff0c;神仙打架&#xff0c;BERT與GPT不分先后。GPT是“Generative Pre-Training”的簡稱&#xff0c;生成式的預訓練。BERT和GPT肯定是GPT難訓練&#xff0c;引用量也是B…

這是一款沒有任何限制的免費遠程手機控制手機的軟件

這是一款沒有任何限制的免費遠程手機控制手機的軟件支持安卓和蘋果1.安裝1.1被控制端安裝airdroid1.2控制端air mirror2.登錄賬號控制端和被控制端登錄同一個賬號3.控制打開控制端軟件選擇要控制的機器直接點“遠程控制“

Observability:更智能的告警來了:更快的分診、更清晰的分組和可操作的指導

作者&#xff1a;來自 Elastic Drew Post 探索 Elastic Stack 告警的最新增強功能&#xff0c;包括改進的相關告警分組、將儀表盤鏈接到告警規則&#xff0c;以及將調查指南嵌入到告警中。 在 9.1 版本中&#xff0c;我們對告警進行了重大升級&#xff0c;幫助 SRE 和運維人員更…

數智之光燃盛景 共同富裕創豐饒

8月29日&#xff0c;2025數博會“一帶一路”國際大數據產業發展暨數智賦能新時代、共同富裕向未來的會議在貴陽國際生態會議中心隆重舉行。作為全球大數據領域的重要盛會&#xff0c;此次活動吸引了來自聯合國機構、國際組織、科研院所、知名企業等社會各界的百余位代表&#x…

【網絡編程】recv函數的本質是什么?

一、為什么說recv函數的本質是 “copy”&#xff1f; recv是用于從網絡連接&#xff08;或其他 IO 對象&#xff09;接收數據的函數&#xff0c;它的核心動作不是 “從網絡上拉取數據”&#xff0c;而是 “把已經到達內核緩沖區的數據復制到用戶程序的緩沖區”。 具體流程拆解&…

JSP程序設計之輸入/輸出對象 — out對象

目錄1、out對象概述2.實例&#xff1a;out對象方法運用輸入/輸出對象&#xff0c;可以控制頁面的輸入和輸出&#xff0c;用于訪問與所有請求和響應有關的數據&#xff0c;包括out、request和response對象。 1、out對象概述 out對象是JspWriter類的一個實例&#xff0c;是一個…

UE里為什么要有提升變量

1、為了簡潔當一個類里面的函數比較多&#xff0c;并且使用比較頻繁的時候&#xff0c;就要不斷的從這個類節點往外拉線&#xff0c;從而獲取不同的函數節點&#xff0c;這樣的藍圖就會看起來比較亂&#xff0c;這時候&#xff0c;就可以將這個常用的類提升為變量。2、為了存儲…

玩轉物聯網只需十行代碼,可它為何悄悄停止維護

文章目錄玩轉物聯網只需十行代碼&#xff0c;可它為何悄悄停止維護1 背景&#xff1a;MQTT 遇上 asyncio&#xff0c;為什么選 hbmqtt&#xff1f;2 hbmqtt 是什么&#xff1f;3 安裝&#xff1a;一行命令&#xff0c;但別裝最新4 五大核心 API&#xff1a;10 行代碼跑通發布訂…

從零開始學大模型之預訓練語言模型

預訓練語言模型 本文較長&#xff0c;建議點贊收藏&#xff0c;以免遺失。更多AI大模型開發 學習視頻/籽料/面試題 都在這>>Github<< >>Gitee<< 3.1 Encoder-only PLM 在上一章&#xff0c;我們詳細講解了給 NLP 領域帶來巨大變革注意力機制以及使用…

JMeter接口測試全流程解析

1. Jmeter的界面介紹和功能組件&#xff08;元件&#xff09;1、測試計劃&#xff1a;Jmeter的起點和容器2、線程組&#xff1a;代表一定的虛擬用戶&#xff08;一個用戶一個線程&#xff09;3、取樣器&#xff1a;發送請求的最小單元4、邏輯控制器&#xff1a;控制組件的執行順…

Effective Modern C++ 條款26:避免在通用引用上重載

在C編程中&#xff0c;函數重載是一項強大的特性&#xff0c;它允許我們為不同的參數類型提供不同的實現。然而&#xff0c;當涉及到通用引用&#xff08;universal references&#xff09;時&#xff0c;重載可能會帶來意想不到的問題。Effective Modern C的條款26明確指出&am…

OpenLayers數據源集成 -- 章節一:圖像圖層詳解

前言在前面的文章中&#xff0c;我們學習了OpenLayers的基礎控件操作。本文將深入探討OpenLayers中的圖像圖層&#xff08;ImageLayer&#xff09;功能&#xff0c;通過一個完整的示例來展示如何使用ImageArcGISRest數據源加載ArcGIS服務&#xff0c;并詳細解釋圖層配置、事件監…

通義萬相wan2.2 Fun系列--Camera鏡頭控制與lnp首尾幀視頻模型

上節內容講解了wan2.2 fun control本節內容對wan2.2 fun系列模型的camera鏡頭控制模型與lnp首尾幀視頻模型進行測試與講解。 Wan2.2-Fun-Camera-Control是阿里基于Wan2.2框架推出的圖生視頻運鏡控制模型 。它支持512、768、1024等多分辨率的視頻預測&#xff0c;以81幀、每秒16…

JavaSE 集合從入門到面試:全面解析與實戰指南

JavaSE 集合從入門到面試&#xff1a;全面解析與實戰指南 在 Java 編程中&#xff0c;集合是處理數據的核心工具&#xff0c;幾乎所有 Java 應用都會用到集合框架。從簡單的列表存儲到復雜的數據分析&#xff0c;集合框架提供了豐富的數據結構和操作方法。本文將從基礎概念到面…

自建云音樂服務器:Navidrome+cpolar讓無損音樂隨身聽

文章目錄前言1. 安裝Docker2. 創建并啟動Navidrome容器3. 公網遠程訪問本地Navidrome3.1 內網穿透工具安裝3.2 創建遠程連接公網地址3.3 使用固定公網地址遠程訪問前言 “想聽自己的無損音樂還要開會員&#xff1f;”——音樂發燒友小王的煩惱。商業音樂平臺音質壓縮&#xff…

C3P0連接池適配HGDB

文章目錄文檔用途詳細信息文檔用途 講解常用的并且需要與數據庫進行交互的開源框架C3P0&#xff0c;以及C3P0框架是如何適配HGDB的。 詳細信息 1.C3P0概述 C3P0是一個開源的JDBC連接池&#xff0c;它實現了數據源和JNDI綁定&#xff0c;支持JDBC3規范和JDBC2的標準擴展。目…

ZeroGPU Spaces 加速實踐:PyTorch 提前編譯全解析

ZeroGPU 讓任何人都能在 Hugging Face Spaces 中使用強大的 Nvidia H200 硬件&#xff0c;而不需要因為空閑流量而長期占用 GPU。 它高效、靈活&#xff0c;非常適合演示&#xff0c;不過需要注意的是&#xff0c;ZeroGPU 并不能在所有場景下完全發揮 GPU 與 CUDA 棧的全部潛能…

8.ImGui-輸入框

免責聲明&#xff1a;內容僅供學習參考&#xff0c;請合法利用知識&#xff0c;禁止進行違法犯罪活動&#xff01; 本次游戲沒法給 內容參考于&#xff1a;微塵網絡安全 上一個內容&#xff1a;7.ImGui-單選框和復選框 單行輸入框使用 ImGui::InputText()&#xff0c;下圖中…