日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java学习笔记: HashMap 和 HashSet

發(fā)布時間:2023/12/18 java 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java学习笔记: HashMap 和 HashSet 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

📒數(shù)據(jù)結構專欄簡介: 內(nèi)容主要以介紹數(shù)據(jù)結構為主, 希望讀者看了之后能有所收獲🉐
👷🏻?作者也是一名剛上路的小白coder🛵, 歡迎各位評論, 批評指正或私信交流👁?🗨~~


文章目錄

  • HashMap
    • 存儲結構
    • 常用方法
      • 構造方法
      • 方法
  • HashSet介紹
    • 存儲結構
    • 常用方法
      • 構造方法
      • 方法
  • 哈希表
    • 基本操作(CURD)
        • 插入(Create) :
        • 搜索(Read):
        • 更新(Update):
        • 刪除(Delete)
    • 哈希沖突
      • 哈希函數(shù)設計
        • 直接定制法
        • 除留余數(shù)法
      • 負載因子的調(diào)節(jié)
    • 哈希沖突的解決辦法
      • 閉散列法
      • 開散列法

關于Map接口和Set接口在上一篇關于TreeMap文章中已經(jīng)介紹過, 這里不再贅述, 詳見: http://t.csdn.cn/L44vx

HashMap

HashMap是Map接口下的一個實現(xiàn)子類, HashMap與TreeMap一樣, 同樣存儲的是<Key, Value>的鍵值對, 與 TreeMap 相同的是, HashMap中的Key 也是唯一的, 當有相同的Key的<Key, Value>, 會更新之前的Value(若Key已存在)

存儲結構

HashMap的存儲容器通常是一個哈希桶, 在存儲的元素過多時, 容器的結構會轉換成一個類似于TreeMap的樹狀結構. 樹中的元素排序依據(jù)主要是哈希值(如果元素對應的類實現(xiàn)了Comparable接口則基于compareTo方法進行比較排序)

我們可以觀察HashMap的源碼進行學習

static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;

哈希表的初始容量是16

static final int MAXIMUM_CAPACITY = 1 << 30;

最大容量是 1 << 30(1073741824)

/** The bin count threshold for using a tree rather than list for a bin. Bins are converted to trees when adding an element to a bin with at least this many nodes. The value must be greater than 2 and should be at least 8 to mesh with assumptions in tree removal about conversion back to plain bins upon shrinkage. */ static final int TREEIFY_THRESHOLD = 8;

樹化的閾值是8, 該閾值必須大于2, 且最小應該是8, 只有這樣才匹配樹容器和普通容器間去樹化轉換的收縮前提

/** The bin count threshold for untreeifying a (split) bin during a resize operation. Should be less than TREEIFY_THRESHOLD, and at most 6 to mesh with shrinkage detection under removal. */ static final int UNTREEIFY_THRESHOLD = 6;

解除樹化的閾值是6, 該閾值應該要小于樹化閾值, 且也要與收縮檢測相匹配

/** The smallest table capacity for which bins may be treeified. (Otherwise the table is resized if too many nodes in a bin.) Should be at least 4 * TREEIFY_THRESHOLD to avoid conflicts between resizing and treeification thresholds. */ static final int MIN_TREEIFY_CAPACITY = 64;

可能樹化的最小容量是64, 而哈希表的擴容大小最小值至少為4*樹化的最小容量

/** The load factor used when none specified in constructor.*/ static final float DEFAULT_LOAD_FACTOR = 0.75f;

默認的負載因子是0.75

負載因子定義:

哈希表的負載因子 α=表中元素個數(shù)表的長度(容量)α = \frac {表中元素個數(shù)}{表的長度(容量)}α=()數(shù)?

當負載因子過大時, 插入新元素時就容易發(fā)生沖突

常用方法

構造方法

方法簡述
HashMap()構造一個具有默認初始容量 (16) 和默認加載因子 (0.75) 的空 HashMap
HashMap(int initialCapacity)構造一個帶指定初始容量和默認加載因子 (0.75) 的空 HashMap
HashMap(int initialCapacity, float loadFactor)構造一個帶指定初始容量和負載因子的空 HashMap
HashMap(Map<? extends K,? extends V> m)構造一個映射關系與指定 Map 相同的新 HashMap

方法

方法簡述
void clear()從map中移除所有映射關系
boolean containsKey(Object key)如果map中包含對于指定鍵的映射關系,則返回 true
boolean containsValue(Object value)如果map中將一個或多個鍵映射到指定值,則返回 true
Set<Map.Entry<K,V>> entrySet()返回map中所包含的映射關系的 Set 視圖
V get(Object key)返回指定鍵所映射的值;如果對于該鍵來說,map中不包含任何映射關系,則返回 null
V put(K key, V value)在此map中關聯(lián)指定值與指定鍵
V remove(Object key)從此映射中移除指定鍵的映射關系(如果存在)
boolean isEmpty()如果map中不包含鍵-值映射關系,則返回 true
int size()返回map中的鍵-值映射關系數(shù)

Map.Entry<K,V>是一個接口, 詳情可見TreeMap介紹文章

HashSet介紹

HashSet實現(xiàn)了Set接口, 存儲的是Key, Key是唯一的

存儲結構

/*** This class implements the <tt>Set</tt> interface, backed by a hash table* (actually a <tt>HashMap</tt> instance). It makes no guarantees as to the* iteration order of the set; in particular, it does not guarantee that the* order will remain constant over time. This class permits the <tt>null</tt>* element. */

由源碼的注釋我們可以知道HashSet是借HashMap實現(xiàn)的, HashSet中的元素排序順序是不能保證的, 且允許儲存null

常用方法

構造方法

方法簡述
HashSet()構造一個新的空 set,其底層 HashMap 實例的默認初始容量是 16,加載因子是 0.75
HashSet(Collection<? extends E> c)構造一個包含指定 collection 中的元素的新 Set
HashSet(int initialCapacity)構造一個新的空 set,其底層 HashMap 實例具有指定的初始容量和默認的負載因子
HashSet(int initialCapacity, float loadFactor)構造一個新的空 Set,其底層 HashMap 實例具有指定的初始容量和指定的負載因子

方法

方法簡述
boolean add(E e)如果 set 中尚未包含指定元素,則添加指定元素
void clear()從 set 中移除所有元素
boolean contains(Object o)如果 set 中包含指定元素,則返回 true
boolean isEmpty()如果 set 中不包含任何元素,則返回 true
boolean remove(Object o)如果指定元素存在于此 set 中,則將其移除
int size()返回此 set 中的元素的數(shù)量(set 的容量)

哈希表

一般的數(shù)據(jù)結構如列表, 鏈表等進行搜索操作時是需要通過遍歷整個表(O(n))才能完成的, 而平衡樹的時間復雜度也是與樹的高度有關(O(logn)), 而我們想要的是一種更高效, 更理想的搜索模式, 就如狙擊槍一般指哪打哪, 達到近似(O(1))的效率, 而Hash Table正是為此而生的.

哈希表(又稱散列表)中通過構造元素中關鍵碼和元素的存儲位置一一對應的映射關系, 使其簡化搜索的過程

基本操作(CURD)

  • 插入(Create) :

    計算出元素對應的哈希值, 依據(jù)哈希值將元素存儲到對應位置

  • 搜索(Read):

    根據(jù)搜索元素中的關鍵字計算出哈希值, 將對應的存儲的元素的哈希值進行比較, 相同則返回其引用

  • 更新(Update):

    與搜索類似, 在搜索的基礎下, 對應哈希值相同則更新

  • 刪除(Delete)

    與搜索類似, 在搜索的基礎下, 對應哈希值相同則將該引用置空

哈希沖突

當哈希表中的元素越來越多時, 總會發(fā)生的情況: 有兩個或多個元素計算出的哈希值而指向同一塊存儲空間, 這就是發(fā)生了哈希沖突(哈希碰撞), 發(fā)生的碰撞越多自然也會降低效率, 這是我們不愿看到的

哈希函數(shù)設計

為了降低發(fā)生哈希沖突的頻率, 在哈希函數(shù)設計上我們可以下一些功夫, 常用的哈希函數(shù)的設計有:直接定制法, 除留余數(shù)法, 平方取中法, 折疊法, 數(shù)學分析法, 在這就簡單介紹兩種常用的方法 直接定制法 和 除留余數(shù)法, 其他方法讀者若有興趣可以自行查找資料, 優(yōu)秀哈希函數(shù)設計可以有效降低哈希沖突發(fā)生的頻率, 但無法完全避免哈希沖突的發(fā)生

直接定制法

取元素中的關鍵字為變量, 通過線性函數(shù)運算得到哈希值(散列地址), 如 :

Hash (Key) = A * Key + B

這種辦法的優(yōu)點是比較簡單, 適用于已知關鍵字范圍, 計算出的地址要數(shù)量不大且分布比較連續(xù)

除留余數(shù)法

同理取元素中的關鍵字為變量, 設哈希表的容量為max, 取最接近或者等于max的質(zhì)數(shù)p(p ≤ m)作為除數(shù), 如 :

Hash (Key) = Key % p

這種方法的優(yōu)缺點與上述方法相似

負載因子的調(diào)節(jié)

哈希沖突發(fā)生的頻率與負載因子也有關, 當哈希表中存儲的元素越多, 負載因子越大, 發(fā)生碰撞的概率也就越高. 所以要對負載因子進行調(diào)節(jié), 從上述負載因子的定義來看, 調(diào)節(jié)負載因子可以改變哈希表的容量

要注意的是調(diào)節(jié)哈希表容量時, 若設計的哈希函數(shù)與哈希表的容量有關, 要將其中存儲的元素重新進行散列地址的計算重新存儲

哈希沖突的解決辦法

閉散列法

當發(fā)生哈希沖突時, 若哈希表的存儲元素個數(shù)還未達到最大, 我們總能找到空位存放發(fā)生沖突的元素

  • 線性探測: 當發(fā)生哈希沖突時, 依次往后尋找到空位即可

如圖上所示, 假設哈希函數(shù)是Hash(Key) = Key % 8, 要插入Key 為 1 的元素, Index 為 1 處已經(jīng)存有 Key 為 9 的元素, 當我們想存入Key為 1 的元素時, 就會發(fā)生沖突, 此時依次往后尋找到 Index 為 2 時有空位, 插入即可

  • 二次探測: 當發(fā)生哈希沖突時, 尋找下一個位置的方法為Hash(Key)=(H0+i2)Hash(Key) = (H_{0} + i^{2} )Hash(Key)=(H0?+i2)% m (H0H_{0}H0?是初次計算出的哈希值, 式中也可以將 H0H_{0}H0?i2i^{2}i2 相減)

如上圖所示, 依然假設哈希函數(shù)是Hash(Key) = Key % 8, 要插入Key 為 17 的元素, Index 為 1 處已經(jīng)存有元素, 通過上述公式計算得下一個 Index 為 2 處, 也存有元素, 則計算第二次得Index 為 5, 為空可插入

開散列法

開散列法則是利用類似鏈表的結構處理沖突, 創(chuàng)建一個存儲哈希桶引用的容器, 當發(fā)生沖突時, 只需用頭插法處理即可

總結

以上是生活随笔為你收集整理的Java学习笔记: HashMap 和 HashSet的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。