[英]Java : HashSet vs. HashMap
我有一個處理大量數據集的程序。 最好將對象存儲在散列實現的容器中,因為程序會繼續在容器中尋找對象。
第一個想法是使用HashMap,因為此容器的get和remove方法更適合我需要的用途。
但是,我發現使用HashMap消耗的內存相當大,這是一個主要問題,因此我認為切換到HashSet會更好,因為它僅對每個元素使用<E>
而不是<K,V>
,但是當我看了我了解到的實現,它使用了底層的HashMap! 這意味着它不會節省任何內存!
所以這是我的問題:
是否還有其他基於散列的容器,它們的內存消耗量將大大減少?
更新
根據注釋中的要求,我將在程序上進行一些擴展,hashMap旨在容納一對其他對象,以及一些數字值-從它們計算得出的float值。 一路上,它會提取其中一些並輸入新對。 對於給定的一對,需要確保不握住該對或將其刪除。 可以使用對對象的float值或hashCode
完成映射。
另外,當我說“巨大的數據集”時,我是在談論〜4 * 10 ^ 9個對象
這個站點上有關於Java集合性能的非常有用的技巧。
HashSet
建立在HashMap< T, Object >
頂部,其中value是單例“存在”對象。 這意味着the memory consumption of aHashSet is identical to HashMap
:要存儲SIZE
值,您需要32 * SIZE + 4 * CAPACITY個字節(加上值的大小)。 絕對不是對內存友好的集合。THashSet可能是
HashSet
的最簡單替換集合-它實現了Set和Iterable,這意味着您應該只在初始化集時更新一個字母。
THashSet
使用單個對象數組作為其值,因此它使用4 * CAPACITY字節進行存儲。 如您所見,與JDK HashSet相比,在相同的加載因子的情況下,您將節省 32 * SIZE字節,這是一個巨大的改進。
另外,我從這里拍攝的以下圖片可以幫助我們牢記某些事項,以選擇合適的收藏
我所有的假設都正確嗎?
您使用HashMap
實現了HashSet
是正確的,因此您不會通過使用HashSet
來節省任何內存。
如果要創建包含大量元素的地圖,則應盡您所知,使用initialCapacity
構造HashMap
,以防止重復進行哈希(從而導致內存顛簸)。
HashMap內存浪費嗎? 更具體地說,每個條目的開銷是多少?
不,這不是浪費。 開銷是一個基礎數組(大小由loadFactor
修改),以及每個鍵值對的Entry
對象。 除了存儲鍵和值外,條目對象還存儲指向插槽中下一個條目的指針(如果兩個或多個條目占用基礎數組中的同一插槽)。 默認的loadFactor為0.75
可將基礎數組的大小保持為條目數的133%。
具體來說,每個條目的內存開銷為:
與基於散列的集合相比,要獲得更多的修剪是非常困難的。
HashSet和HashMap一樣浪費嗎?
使用HashSet
而不是HashMap
不會獲得任何內存效率。
是否還有其他基於散列的容器,它們的內存消耗量將大大減少?
如果您的鍵是基元(例如int
),則那里( 第三方庫中 )有自定義的Map
和Set
實現,它們使用內存效率更高的數據結構。
確實,HashSet使用的內存與HashMap一樣多。 HasSet實現Set的兩者之間的區別,即,它不關心與某個鍵關聯的任何值,僅關心是否存在特定值。 HashMap與每個鍵的值的存儲/檢索(放置/獲取)有關。
雖然HashMap / HashSet將數據存儲在通常比元素數稍大的數組中,但由於負載因子為0.75,因此此保留並不是太大的問題。 這意味着,當元素數量達到基礎數組大小的75%時,HashMap將增長。
與大地圖相比,更大的問題是很多空地圖,因為HashMap的默認大小為16。這可以通過將初始容量設置為0來抵消。
但是,您也可以改用TreeMap,因為TreeMap是基於引用而不是數組的,所以您可能會浪費更多的空間,尤其是使用較大的地圖時,除了會損失一些速度。 TreeMap的主要優點在於,它會將鍵保持在有序狀態,因此,如果需要對它們進行排序,那是必須走的路。
此外,當您不能或不想對鍵類型的equals
和hashCode
方法進行自定義實現時,由於編程原因,可以使用TreeMap。 您可以改用密鑰類型的比較器。 例如,要基於不區分大小寫的字符串創建映射/集合,請使用String.CASE_INSENSITIVE_ORDER
作為TreeSet的比較器
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.