HashMap

基礎知識:java

數組:數組

  • 存儲連續,佔用內存嚴重;
  • 空間複雜度大,數組的二分查找時間複雜度小,
  • 尋址容易,插入、刪除困難;
鏈表:
  • 存儲區間散列,佔用內存寬鬆,空間複雜度小,時間複雜度大 O(N)
  • 尋址困難,插入、刪除容易
哈希表:
  •  尋址容易,插入刪除也容易;
  •  數組+鏈表
  •  長度爲16的數組,每一個元素存儲鏈表的頭節結點;
  •  數組的下標:hash(key)%len--元素key的哈希值對數組長度取模;
  • 實現了靜態內部類Entry來存值;即Map裏面的內容保存在Entry[]裏面;
  • 存數據:
key--hash取模Entry長度--index下標--下標對應的值;
  • 取數據
key--hash取模Entry長度--index下標--返回下標對應的值;
  • null key老是存放在Entry[]數組的第一個元素。
哈希衝突:
  • 理想哈希函數:
同一個輸入值,產生相同的哈希值;
不一樣的輸入值,產生不一樣的哈希值;
  • 哈希衝突:
不一樣的輸入值,產生相同的哈希值;
 
SQL Server內置的三個哈希函數
校驗和函數:
checksum;
binary_checksum
HashBytes
注意:業務邏輯要求不容許有偏差,不要使用任何的哈希函數;只要是哈希函數,就會存在衝突;
 // 強烈建議不要在項目中使用校驗和函數
//binary_checksum 和 checksum 產生的校驗和的質量比較低,建議不要再項目中使用校驗函數。當字符串比較短時,很大可能產生Hash 衝突
 
解決哈希衝突的方法:
 

解決hash衝突的辦法

  1. 開放定址法(線性探測再散列,二次探測再散列,僞隨機探測再散列)
  2. 再哈希法
  3. 鏈地址法
  4. 創建一個公共溢出區
Java中hashmap的解決辦法就是採用的鏈地址法。
 
具體以下:

建立哈希表和查找哈希表都會遇到衝突,兩種狀況下解決衝突的方法應該一致。下面以建立哈希表爲例,說明解決衝突的方法。經常使用的解決衝突方法有如下四種:函數

1.開放定址法spa

這種方法也稱再散列法,其基本思想是:當關鍵字key的哈希地址p=H(key)出現衝突時,以p爲基礎,產生另外一個哈希地址p1,若是p1仍然衝突,再以p爲基礎,產生另外一個哈希地址p2,…,直到找出一個不衝突的哈希地址pi ,將相應元素存入其中。.net

2. 再哈希法指針

    這種方法是同時構造多個不一樣的哈希函數:對象

    Hi=RH1(key)  i=1,2,…,k排序

當哈希地址Hi=RH1(key)發生衝突時,再計算Hi=RH2(key)……,直到衝突再也不產生。這種方法不易產生彙集,但增長了計算時間。繼承

3. 鏈地址法接口

    這種方法的基本思想是將全部哈希地址爲i的元素構成一個稱爲同義詞鏈的單鏈表,並將單鏈表的頭指針存在哈希表的第i個單元中,於是查找、插入和刪除主要在同義詞鏈中進行。鏈地址法適用於常常進行插入和刪除的狀況。

4.創建公共溢出區

這種方法的基本思想是:將哈希表分爲基本表和溢出表兩部分,凡是和基本表發生衝突的元素,一概填入溢出表

 
 
 

Map :

基於鍵-值映射的關係來搭建存儲結構,在整個結構中使用key值來惟一標識對象.(在JDK1.2以後出現用於替換原有API中的Dictionary類的做用)。經常使用方法:                                   

                     put(key,value)

                       get(key)

 

                       remove()

 

                       values():將結構中存儲的全部值都以對象的形式返回

 

                       keySet():將結構中的全部key值,以set結構返回.

 

 實現類:

 HashMap

  TreeMap: –底層基於二叉樹結構來存儲數據,會根據key來做爲二叉樹的節點關鍵屬性來進行排序操做,按key值的從小到大進行排列

1.1.1.1. Map集合闡述

//遍歷map

for (Entry<String, Integer> entry : hm.entrySet()) {

System.out.println("name:"+entry.getKey()+"------"+"age:"+entry.getValue());

}

Map接口不是Collection接口的繼承。Map接口用於維護鍵/值對(key/value pairs)。該接口描述了從不重複的鍵到值的映射。

  (1) 添加、刪除操做:
  Object put(Object key, Object value): 將互相關聯的一個關鍵字與一個值放入該映像。若是該關鍵字已經存在,那麼與此關鍵字相關的新值將取代舊值。方法返回關鍵字的舊值,若是關鍵字原先並不存在,則返回null
  Object remove(Object key): 從映像中刪除與key相關的映射
  void putAll(Map t): 未來自特定映像的全部元素添加給該映像
  void clear(): 從映像中刪除全部映射
  「鍵和值均可覺得null。可是,您不能把Map做爲一個鍵或值添加給自身。」
  (2) 查詢操做:
  Object get(Object key): 得到與關鍵字key相關的值,而且返回與關鍵字key相關的對象,若是沒有在該映像中找到該關鍵字,則返回null
  boolean containsKey(Object key): 判斷映像中是否存在關鍵字key
  boolean containsValue(Object value): 判斷映像中是否存在值value
  int size(): 返回當前映像中映射的數量
  boolean isEmpty() :判斷映像中是否有任何映射
  (3) 視圖操做 :處理映像中鍵/值對組
  Set keySet(): 返回映像中全部關鍵字的視圖集
  「由於映射中鍵的集合必須是惟一的,您用Set支持。你還能夠從視圖中刪除元素,同時,關鍵字和它相關的值將從源映像中被刪除,可是你不能添加任何元素。」
  Collection values():返回映像中全部值的視圖集
  「由於映射中值的集合不是惟一的,您用Collection支持。你還能夠從視圖中刪除元素,同時,值和它的關鍵字將從源映像中被刪除,可是你不能添加任何元素。」
  Set entrySet(): 返回Map.Entry對象的視圖集,即映像中的關鍵字/值對
  「由於映射是惟一的,您用Set支持。你還能夠從視圖中刪除元素,同時,這些元素將從源映像中被刪除,可是你不能添加任何元素。」
  Map.Entry接口
  Map的entrySet()方法返回一個實現Map.Entry接口的對象集合。集合中每一個對象都是底層Map中一個特定的鍵/值對。

經過這個集合的迭代器,您能夠得到每個條目(惟一獲取方式)的鍵或值並對值進行更改。當條目經過迭代器返回後,除非是迭代器自身的remove()方法或者迭代器返回的條目的setValue()方法,其他對源Map外部的修改都會致使此條目集變得無效,同時產生條目行爲未定義。
  (1) Object getKey(): 返回條目的關鍵字
  (2) Object getValue(): 返回條目的值
  (3) Object setValue(Object value): 將相關映像中的值改成value,而且返回舊值

補充:Entry是Map中用來保存一個鍵值對的,而Map實際上就是多個Entry的集合。Entry是Map實現類的內部類。看下HashMap實現源碼,就明白Entry的做用了。

相關文章
相關標籤/搜索