簡體   English   中英

在ULONG作為鍵且未知存儲區計數的Unordered_map(C ++)中,insert需要花費很長時間

[英]insert is taking long long time in an Unordered_map (C++) with ULONG as key and unknown bucket count

我有一個key為ULONG的unordered_map。

我知道可以有很多條目,但不確定多少。 因此無法事先指定存儲桶數。 我期望插入的時間復雜度為O(1),因為鍵是唯一的。 但是似乎插入物需要很長時間。

我已經讀到,如果沒有指定存儲桶數,這會花費很多時間,但是如果進行大量的重新哈希處理,這可能是可能的。

我有什么辦法可以改善此處插入的時間復雜度。 還是我錯過了什么?

可能有幫助的幾件事:

  1. 實際上,您可以計算出何時進行重新哈希處理,然后解決問題。 來自cplusplus.com

“如果在插入操作后新的容器大小增加到其容量閾值以上(按容器的bucket_count乘以其max_load_factor計算),則將強制進行重新哈希處理。”

  1. 嘗試隔離插入操作,看它是否確實花了很長時間,否則編寫一個簡單的計時器,並將其放置在代碼中的有用位置,以查看消耗時間的位置

max_load_factor和搶先調用reserve ,您應該既可以使重新哈希最小化,又可以使存儲桶沖突最小化。 保持平衡主要是性能測試的問題。

首先,許多標准庫實現都使用標識函數(即hash(x) == x整數進行hash(x) == x 通常這是可以的,尤其是在實現確保存儲桶計數為素數的情況下(例如GCC),但是某些實現使用二乘冪存儲桶計數(例如Visual C ++)。 您可以通過哈希函數運行一些數字,看看它是否是一個身份函數:如果是,請考慮您的輸入是否足夠隨機,以至於無關緊要。 例如,如果您的數字都是4的倍數,則2的冪數存儲桶計數意味着您只使用了四分之一的存儲桶。 如果它們傾向於在高階位中變化最大,這也是一個問題,因為具有2的冪的存儲桶計數的按位與有效地丟棄了一些高階位(例如,對於1024個存儲桶,只有10個最低有效位散列值的位將影響存儲區選擇)。

檢查此類問題的一種好方法是遍歷存儲桶並創建碰撞元素數量的直方圖,例如-給定unordered_map m

std::map<int, int> histogram;
for (size_t i = 0; i < m.bucket_count(); ++i)
    ++histogram[m.bucket_size(i)];
for (auto& kv : histogram)
    std::cout << ".bucket_size() " << kv.first << " seen "
              << kv.second << " times\n";

(您可以在此處看到運行的代碼)。

您希望較大的bucket_size()值的頻率很快消失:如果不是,請使用您的哈希函數。

另一方面,如果您過度使用512位密碼散列或其他方法實例化了unordered_map ,那也不必要地減慢了表操作的速度。 對於元素少於40億個表的日常使用,您需要考慮的最強哈希是32位雜音哈希。 但是,除非上面報告的沖突有問題,否則請使用提供的標准庫。

如果您沒有很多“攪局”, 那么切換到封閉式尋址/開放式哈希表實現(您可能會用Google來實現)可能會更快得多:刪除哈希表元素幾乎與插入新元素一樣多,其中穿插了查找。 封閉式尋址意味着哈希表鍵直接存儲在存儲桶中,並且隨着表大小的增加,您可以獲得更好的緩存命中率和更快的重新哈希。 如果您的整體鍵映射到的值很大(在內存方面,如sizeof(My_Map::value_type) ),請確保實現僅將指向它們的指針存儲在表本身中,因此不需要整個對象在調整大小時復制。

注意:以上假設哈希表確實引起了您的性能問題。 如果有任何疑問,請使用探查器確認是否還沒有。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM