03.Java數據結構與算法之~HashMap
HashMap的原理
底層結構是哈希表,採用了順序表+鏈表結合結構;同一個鏈表的上所有元素的存儲地址都是相同的,是發生衝突的元素
鏈表上每個節點的就是一個Entry,字段包括四部分
哈希碼可能不相同,存儲地址相同。
哈希表的優點
添加快、查詢快(通過計算得到存儲位置,不是通過比較) 無序 (key)唯一關鍵參數
默認主數組長度16; 默認裝填因子0.75。 每次主數組擴容爲原來的2倍 JDK8,當鏈表長度大於8,鏈表變成紅黑樹
第一步計算哈希碼,不僅調用了hashCode(),有進行了多次散列。目的在於key不同,哈希碼儘量不同,減少衝突
細節:發生衝突,經過比較不存在相同key的元素,要添加一個新的節點。不是加到鏈表最後,而是添加到鏈表最前
定義Map接口
public interface Map {
//定義方法
void put(Object key,Object value);
Object get(Object key);
int size();
boolean isEmpty();
String toString();
//定義內部接口
interface Entry{
public Object getKey();
public Object getValue();
}
}
接口的實現
public class HashMap implements Map{
private Node[] node;
int size;
public HashMap(int capacity){
node = new Node[capacity];
}
public HashMap(){
this(16); //默認初始爲16
}
//-------實現主要方法-------
@Override
public void put(Object key, Object value) {
//計算哈希碼
int hash = key.hashCode();
//根據哈希碼計算存儲位置
int index = hash % node.length;
//如果放入數據的位置有數據
if(node[index] != null){
//鍵不重複
Node current = node[index];
while(current != null){
//如果鍵相同
if(current.key.equals(key)){
//覆蓋值
current.value = value;
//因爲鍵相同所以只是覆蓋,並非新增,因此提前return
//防止後面size++導致數據錯亂
return;
}
//遍歷
current = current.next;
}
//創建新的節點
Node newNode = new Node(hash,key,value);
//讓新的節點下一個爲原來的節點
newNode.next = node[index];
//存儲新的開始節點
node[index] = newNode;
}else{
//放入數據的位置沒有數據,直接放入
node[index] = new Node(hash,key,value);
}
//如果沒有發現相同的鍵,則長度增加
size++;
}
@Override
public Object get(Object key) {
//計算哈希碼
int hash = key.hashCode();
//根據哈希碼計算存儲位置
int index = hash % node.length;
//查找對應的Entry
Node entry = null;
if (node[index] != null) {
Node currentEntry = node[index];
while (currentEntry != null) {
if (currentEntry.getKey().equals(key)) {
entry = currentEntry;
break;
}
//向後移動鏈表
currentEntry = currentEntry.next;
}
}
return entry == null ? null : entry.getValue();
}
@Override
public String toString(){
StringBuilder builder = new StringBuilder("{");
for(int i=0;i<node.length;i++){
if(node[i] != null){
Node entry = node[i];
while(entry != null){
builder.append(entry.getKey()+"="+entry.getValue()+",");
entry = entry.next;
}
}
}
if(builder.length()!=1){
//刪除逗號
builder.deleteCharAt(builder.length()-1);
}
builder.append("}");
return builder.toString();
}
@Override
public int size() {
return size;
}
@Override
public boolean isEmpty() {
return size == 0;
}
//-------定義內部類實現Entry接口-------
class Node implements Map.Entry{
int hash; //存儲鍵的哈希碼
Object key; //鍵
Object value; //值
Node next; //下一個節點
@Override
public Object getKey() {
return key;
}
@Override
public Object getValue() {
return value;
}
//-------構造-------
public Node() { }
public Node(int hash, Object key, Object value) {
this.hash = hash;
this.key = key;
this.value = value;
}
public Node(int hash, Object key, Object value, Node next) {
this.hash = hash;
this.key = key;
this.value = value;
this.next = next;
}
//-------toString-------
public String toString() {
if (next != null) {
return "{" + key + ":" + value + "-" + hash + " " + next + "}";
} else {
return "{" + key + ":" + value + "-" + hash + "}";
}
}
}
}