手寫代碼:HashMap

一、簡介

1、原理解析

Entry[ ] table 就是HashMap的核心數組結構,我們也稱之爲“位桶數組”;
一個Entry對象存儲了:

  1. key:鍵對象 value:值對象

  2. next:下一個節點

  3. hash: 鍵對象的hash值

顯然每一個Entry對象就是一個單向鏈表結構,我們使用圖形表示一個Entry對象的典型示意:
在這裏插入圖片描述
然後,我們畫出Entry[]數組的結構(這也是HashMap的結構):

在這裏插入圖片描述
存儲過程

在這裏插入圖片描述

2、單個方法原理解析

1、根據key的hash值,確定存儲的位置(取模)

根據key的hash值,取模確定一個值(值小於桶),實現隨機存儲在桶中;

2、存儲元素(key-value)

創建存儲對象,添加值到Node元素對象中,存的過程分爲三種情況。

(1): 獲取的桶元素爲空,直接將當前元素存進去即可;

(2): 遍歷當前桶中元素,如果有相同key,則把value值進行替換;

(3): 遍歷當前桶中元素,如果沒有重複的key,則把值添加到最後;

3、重寫toString方法

創建StringBuilder進行存儲,遍歷桶,再將桶中的鏈表的進行遍歷,取出其中存儲的value的值,進行返回;

4、get方法

根據1、方法獲取key特定的hash值,找到指定的桶,遍歷其中的鏈表,根據key的值,取出value值返回即可。

二、實現的代碼

Node

public class Node<K, V> {

    public int hash;    //key的hash值
    public K key;       //key鍵的的值
    public V value;     //存儲的value值
    public Node next;   //下一個元素的地址值
}

HashMap

public class MyHashMap<K, V> {

    Node[] table;    //位桶數組
    int size;       //存放的鍵值對的個數

    public MyHashMap() {
        table = new Node[16];
    }

    public MyHashMap(Node[] table, int size) {
        this.table = table;
        this.size = size;
    }

    //    1、根據key的hash值,確定存儲的位置(取模)
    private int myHash(int v, int length) {
        return v & (length - 1);
    }

    //    2、存儲元素(key-value)
    public void put(K key, V value) {
//        -1、創建存儲的對象,並把值放進去
        Node newNode = new Node();
        newNode.hash = myHash(key.hashCode(), table.length);
        newNode.key = key;
        newNode.value = value;
        newNode.next = null;

//        -2、將有值的對象,放進hashMap對象的存儲位置中
        Node temp = table[newNode.hash];

        Node iterLast = null;     //正在遍歷的最後一個元素
        boolean keyRepeat = false;

        if (temp == null) {
            //1、此處數組元素爲空,則直接將節點放進去
            table[newNode.hash] = newNode;
            size++;
        } else {
//           2、此處數組元素不爲空。則遍歷對應鏈表
            while (temp != null) {
                if (temp.key.equals(key)) {
                    keyRepeat = true;
                    temp.value = value;  //只是覆蓋value的值即可。其他的(hash,key,next)值保持不變
                    break;
                } else {
//                     key不重複,則遍歷下一個
                    iterLast = temp;
                    temp = temp.next;
                }
            }
//             3、沒有發生key重複的情況,則添加到鏈表的最後
            if (!keyRepeat) {
                iterLast.next = newNode;
                size++;
            }
        }
    }


    //    3、重寫toString方法
    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder("{");

//        遍歷bucket數組
        for (int i = 0; i < table.length; i++) {
            Node temp = table[i];

//            遍歷鏈表
            while (temp != null) {
                sb.append(temp.key + ":" + temp.value);
                temp = temp.next;
            }
        }
        sb.setCharAt(sb.length() - 1, '}');
        return sb.toString();
    }


    //    4、get方法
    public V get(K key) {
        int hash = myHash(key.hashCode(), table.length);
        V value = null;

        if (table[hash] != null) {
            Node temp = table[hash];

            while (temp != null) {
//                相等:則說明找到了鍵值對,返回相應的value值
                if (key.equals(temp.key)) {
                    value = (V) temp.value;
                    break;
                } else {
                    temp = temp.next;
                }
            }
        }
        return value;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章