日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

hashmap赋值给另一个hashmap_图解设计一个 HashMap

發布時間:2025/3/20 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 hashmap赋值给另一个hashmap_图解设计一个 HashMap 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

目前我們學到的數據結構有:單鏈表,雙向鏈表,棧,隊列,循環隊列,雙端隊列。今天學習 LeetCode 的 「 706. Design HashMap 」,從設計一個 HashMap 到掌握其內部原理。題目要求:

Design a HashMap without using any built-in hash table libraries.
To be specific, your design should include these functions:put(key, value) : Insert a (key, value) pair into the HashMap. If the value already exists in the HashMap, update the value.get(key): Returns the value to which the specified key is mapped, or -1 if this map contains no mapping for the key.remove(key) : Remove the mapping for the value key if this map contains the mapping for the key.

? All keys and values will be in the range of [0, 1000000].

The number of operations will be in the range of?[1, 10000].

題目要求設計一個 HashMap,不能使用語言提供的類似哈希表的庫,比如HashMap,dict,map,需要實現下面幾個方法:

1. put(key, value) : 根據 key 插入一個 value,如果 key 已經存在,更新 value;

2. get(key): 根據一個 key 獲取對應的值,如果未找到對應的 value,返回 -1;

3. remove(key) : 根據 key 來刪除對應的值。

分析

HashMap 是一種典型的以空間換取時間的數據結構,在設計緩存算法 LRU 和 LFU 當中用到了 C++ 提供的 unorder_map,利用HashMap 的特點,做到存取時間復雜度為 O(1) 。今天我們要掌握如何設計一個 HashMap。設計之前需要知道?HashMap 是一種什么樣的數據結構?

HashMap 的核心思想是 「 把 key 通過一種方式轉換成一個 hashCode(一個整形數),通過 hashCode 來存取對應的 value 」,轉換的方式就是哈希函數,在轉換的過程中,不同的 key 可能會生成同一 hashCode,這將產生「哈希沖突」。

一圖勝千言!

插入 key 對應的 value 函數為:put(key, value):

執行 put(1, 1),1 的 hash 值 hash(1) = 1 % 5 = 1,放到 1 個位置;

執行 put(4, 4),4 的 hash 值 hash(4) = 4 % 5 = 4,放到 4 個位置;

執行 put(6, 6),6 的 hash 值 hash(6) = 6 % 5 = 1,放到 1 個位置,第一個位置已經存放了 1,產生「哈希沖突」;

綜上,設計一個哈希表需要做下面 2 件事:

1.設計哈希函數;

衡量一個哈希函數設計的好壞是看它是否能夠讓 value 「均勻分布」,也就是產生哈希沖突越少越好。語言本身一般會提供計算 hashCode 的方法,比如 OC 中的 NSObject 類提供了 hash 方法:

NSString *name = @"Lefe_x";NSString?*des?=?@"超越技術公眾號做圖解算法";NSLog(@"hash(name)?=?%@,?hash(des)=%@",?@(name.hash),?@(des.hash));// hash(name) = 7306077673678745, hash(des)=7723704617483326955

2.解決哈希沖突;

不同的 key 生成的 hashCode 相同就產生了哈希沖突,解決沖突有主要有下面幾種方式:

鏈地址法:產生哈希沖突后,把產生沖突的元素使用某種方式「組合」到一起,可以使用鏈表、紅黑樹,或者使用其它數據結構。

把 1、6、3、4、13 分別 put 到哈希表中,1、6、13 的哈希值均為 1,被放到第一個位置,可以通過鏈表、紅黑樹進行存儲。

開地址法:產生哈希沖突后,把 value 放到其它空閑位置,可以使用線性探測法放到下一個空閑位置;使用平方探測法,放到第1個、第 4個、第9個、第16個......空閑位置;使用二次哈希,通過另外一個哈希函數再計算一次哈希值。

使用線性探測法解決沖突,把 1、6、3、4、13 分別 put 到哈希表中,1、6、13 的哈希值均為 1,會產生沖突,當遇到沖突后,把 value 插入到下一個位置。保存結果如下圖:

代碼

通過上面的分析可知,實現一個 HashMap,需要一個實現一個哈希函數和解決哈希沖突,代碼中通過「鏈地址法」來解決哈希沖突。題目中的 key 和 value 的取值范圍為 [ 0 - 1000000 ]。代碼原理如圖:

C++ 代碼如下(來源于 LeetCode):

#include #include #include using?namespace?std;class MyHashMap { size_t m_size = 10000; vector<listint, public: // 初始化,設置大小 MyHashMap() { m_data.resize(m_size); } // 哈希函數 int hashCode(int key) { return key % m_size; } // 根據 key 存儲對應的 value,如果 key 已經存在,更新 value void put(int key, int value) { // 根據哈希函數找到對應的鏈表 auto &list = m_data[hashCode(key)]; for (auto & val : list) { // 如果已經存在,根據 key 來更新對應的值 if (val.first == key) { val.second = value; return; } } // 插入鏈表的尾部 list.emplace_back(key, value); } // 根據 key 來獲取值 int get(int key) { const auto &list = m_data[hashCode(key)]; if (list.empty()) { return -1; } for (auto & val : list) { // 如果已經存在,找到了對應的值 if (val.first == key) { return val.second; } } return -1; } // 根據 key 刪除對應的值 void remove(int key) { auto &list = m_data[hashCode(key)]; // 找到節點后刪除 list.remove_if([key](auto n) { return n.first == key; }); }};

總結

至此,一個簡單的 HashMap 就完成了,如果設計一個復雜的 HashMap,需要考慮數據達到一定程度后,需要對 vector 進行擴容、縮容處理,如果沖突達到某一個量級后,需要考慮更換 list 這個數據結構,比如換成紅黑樹。

推薦閱讀:

論證:學習數據結構和算法很重要

圖解 LFU cache

圖解數據結構和算法

總結

以上是生活随笔為你收集整理的hashmap赋值给另一个hashmap_图解设计一个 HashMap的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。