簡體   English   中英

如何將13位值映射到4位代碼?

[英]How to map 13 bit value to 4 bit code?

我有一個std :: map用於某些數據包處理程序。

在分析之前我沒有注意到,但不幸的是,這個地圖查找單獨消耗大約10%的CPU時間(稱為太多時間)。

通常,輸入數據中最多只存在10個鍵。 所以我試圖在地圖前面實現一種密鑰緩存。

鍵值為13位整數。 我知道只有8192個可能的鍵和8192個項目的數組可以提供恆定的時間查找但我覺得已經慚愧,不想使用這樣一個天真的方法:(

現在,我只是猜測一些散列方法,可以非常快速地為13位整數產生4位代碼值。

有什么好主意嗎?

提前致謝。

UPDATE

除了我的恥辱,我沒有完全控制源代碼,並且幾乎禁止為此目的制作新陣列。

項目經理說(誰運行了探查器)鏈表顯示小的性能增益,並建議使用std :: list而不是std :: map。

UPDATE

密鑰的值是隨機的(沒有關系)並且沒有良好的分布。

樣品:
1)0x100,0x101,0x10,0x0,0xffe
2)0x400,0x401,0x402,0x403,0x404,0x405,0xff

假設您的哈希表包含一些基本類型 - 它幾乎沒有內存。 即使在64位系統上,它也只有64kb的內存。 使用像這樣的查找表沒有任何恥辱,它具有一些你可以獲得的最佳性能。

除非您正在編寫某種類型的嵌入式系統,其中8K非常重要,否則只需使用該陣列並繼續前進。 如果你真的堅持做其他事情,你可能會考慮一個完美的哈希生成器(例如, gperf )。

如果您的表中確實只有10個活動條目,您可能會認真考慮使用未排序的向量來保存此映射。 像這樣的東西:

typedef int key_type;
typedef int value_type;
std::vector<std::pair<key_type, value_type> > mapping;

inline void put(key_type key, value_type value) {
    for (size_t i=0; i<mapping.size(); ++i) {
        if (mapping[i].first==key) {
            mapping[i].second=value;
            return;
        }
    }
    mapping.push_back(std::make_pair(key, value));
}    

inline value_type get(key_type key) {
    for (size_t i=0; i<mapping.size(); ++i) {
        if (mapping[i].first==key) {
            return mapping[i].second;
        }
    }
    // do something reasonable if not found?
    return value_type();
}

現在,這些算法的漸近速度(每個O(n) )比你用紅黑樹(比如在O(log n) std::map )或哈希表( O(1) )更糟糕。 O(1) )。 但是你並不是在談論處理大量物體,所以漸近估計並不能真正為你買單。

另外, std::vector為你帶來低開銷和引用的局部性, std::mapstd::list都不能提供。 因此,小std::vector更可能完全保留在L1緩存中。 由於幾乎可以肯定是導致性能問題的內存瓶頸,使用std::vector甚至算法選擇不當可能比樹或鏈表更快。 當然,只有少數可靠的配置文件會告訴您。

當然算法可能是更好的選擇:有序矢量可能會提供更好的性能; 一個調整良好的小哈希表可能也可以。 我懷疑你會很快遇到Amdahl定律試圖改進一個簡單的未分類矢量。 很快,您可能會發現自己遇到了函數調用開銷或其他一些此類問題,作為您的配置文件的一個重要貢獻者。

您可能希望使用中間解決方案和開放尋址技術:一個大小為256的數組。數組的索引是一些簡單的散列函數,如兩個字節的XOR。 數組的元素是struct {key,value}。 通過將碰撞元素存儲在下一個可用索引處來處理沖突。 如果需要從數組中刪除元素,並且刪除很少,則只需重新創建數組(從剩余元素創建臨時列表,然后從此列表創建數組)。

如果您巧妙地選擇哈希函數,幾乎不會發生任何沖突。 例如,從你的兩個例子中,一個這樣的散列將是低字節的高字節的XOR低半字節(並且用剩余的第13位做你喜歡的事情)。

我同意GWW,你最終沒有使用這么多內存......但是如果你願意,你可以使用11或13個鏈表的數組,並使用%函數散列鍵。 如果密鑰數小於數組大小,則復雜性帳篷仍為O(1)。

當你總是只有十個鍵時,使用一個列表(或數組)。 做一些基准測試,以確定是否使用排序列表(或數組)和二進制搜索將提高性能。

您可能首先想要查看是否有任何不必要的密鑰查找調用。 理想情況下,你只希望每個數據包執行一次 - 每次調用一個函數時都會有一些開銷,所以擺脫額外的調用是好的。

映射通常非常快,但如果鍵被映射到項目的方式中有任何可利用的模式,您可以使用它並可能做得更好。 您能否提供有關密鑰和相關4位值的更多信息? 例如,他們是順序的,是否有某種模式?

最后,正如其他人所提到的,查找表非常快,8192個值* 4位僅為4kb,確實存在少量內存。

我會使用查找表。 除非你使用微控制器或其他東西,否則它很小。

否則我會這樣做 -

生成一個30個元素的表格。 對於每個查找計算哈希值(鍵%30)並將其與表中該位置的存儲密鑰進行比較。 如果鑰匙在那里,那么你找到了你的價值。 如果插槽為空,則添加它。 如果密鑰錯誤,則跳到下一個空閑單元格並重復。

使用30個單元和10個鍵沖突應該是罕見的,但是如果你得到一個,它可以快速跳到下一個單元,而正常的查找只是模數和比較操作,所以相當快

暫無
暫無

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

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