好程式設計師大資料學習路線分享什麼是Hash表

好程式設計師IT發表於2019-09-27

  好程式設計師大資料學習路線分享 什麼是Hash ,Hash ,一般翻譯做“雜湊”,也有直接音譯為“雜湊”的,它是基於快速存取的角度設計的,也是一種典型的“空間換時間”的做法。顧名思義,該資料結構可以理解為一個線性表,但是其中的元素不是緊密排列的,而是可能存在空隙。

 

 雜湊表( Hash table ,也叫雜湊表),是根據關鍵碼值 (Key value) 而直接進行訪問的資料結構。也就是說,它透過把關鍵碼值對映到表中一個位置來訪問記錄,以加快查詢的速度。這個對映函式叫做雜湊函式,存放記錄的陣列叫做雜湊表。比如我們儲存 70 個元素,但我們可能為這 70 個元素申請了 100 個元素的空間。 70/100=0.7 ,這個數字稱為負載 ( 載入 ) 因子。我們之所以這樣做,也 是為了“快速存取”的目的。我們基於一種結果儘可能隨機平均分佈的固定函式 H 為每個元素安排儲存位置,以達到快速存取。但是由於此隨機性,也必然導致一個問題就是衝突。所謂衝突,即兩個元素透過雜湊函式 H 得到的地址相同,那麼這兩個元素稱為“同義詞”。這類似於 70 個人去一個有 100 個椅子的飯店吃飯。雜湊函式的計算結果是一個儲存單位地址,每個儲存單位稱為“桶”。設一個雜湊表有 m 個桶,則雜湊函式的值域應為 [0,m-1] 。  

 

   這些元素是按照什麼樣的規則儲存到陣列中呢。一般情況是透過hash(key)%len 獲得,也就是元素的 key 的雜湊值對陣列長度取模得到。比如上述雜湊表中, 12%16=12,28%16=12,108%16=12,140%16=12 。所以 12 28 108 以及 140 都儲存在陣列下標為 12 的位置

 

2.hash 表擴容的理解

 

可是當雜湊表接近裝滿時, 因為陣列的擴容問題 , 效能較低 ( 轉移到更大的雜湊表中 ).

 

Java 預設的雜湊單元大小全部都是 2 的冪,初始值為 16 2 4 次冪)。假如 16 條連結串列中的 75% 連結有資料的時候,則認為載入因子達到預設的 0.75 HahSet 開始重新雜湊,也就是將原來的雜湊結構全部拋棄,重新開闢一個雜湊單元大小為 32 2 5 次冪)的雜湊結果,並重新計算各個資料的儲存位置。以此類推下去 .....

 

負載( 載入 ) 因子 :0.75.-->hash 表提供的空間是 16  也就是說當到達 12 的時候就擴容

 

3. 排重機制的實現

 

假如我們有一個資料( 雜湊碼 76268) ,而此時的 HashSet 128 個雜湊單元,那麼這個資料將有可能插入到陣列的第 108 個連結串列中 (76268%128=108) 。但這只是有可能,如果在第 108 號連結串列中發現有一個老資料與新資料 equals()=true 的話,這個新資料將被視為已經加入,而不再重複丟入連結串列。

 

4. 優點

 

雜湊表的插入和查詢是很優秀的.

 

對於查詢: 直接根據資料的雜湊碼和雜湊表的陣列大小計算除餘後,就得到了所在陣列的位置,然後再查詢連結串列中是否有這個資料即可。因為陣列本身查詢速度快 , 所以查詢的效率高低體現在連結串列中,但是真實情況下在一條連結串列中的資料又很少,有的甚至沒有 , 所以幾乎沒有什麼迭代的代價。所以雜湊表的查詢效率建立在雜湊單元所指向的連結串列中資料的多少上 .

 

對於插入: 陣列的插入速度慢 , 而連結串列的插入速度快 . 當我們使用雜湊表時 , 不需要更改陣列的結構 , 只需要在找到對應的陣列下標後 , 進入對應的連結串列 , 操作連結串列即可 . 所以 hash 表的整體插入速度也很快 .

 

5. 模擬實現程式碼

 

Node

 

```

public class Node {

// key、value模擬鍵值對的資料

    public Integer key;

    public String value;

    // 下一節點的引用

    public Node next;

    public Node() {

    }

    public Node(int key, String value) {

        this.key = key;

        this.value = value;

    }

 

}

```

 

MyLinkedList

 

```

    public class MyLinkedList {

    // 根節點

    private Node root;

 

    public MyLinkedList() {

        root = new Node();

    }

    /**

     * 新增資料,key值必須唯一,如果重複值將被覆蓋

     * @param key

     */

    public void add(int key, String value) {

 

        Node newNode = new Node(key, value);

        Node current = root;

        while (current.next != null) {

            if(current.next.key == key) {

                current.next.value = value;

                return;

            }

            current = current.next;

        }

        current.next = newNode;

    }

 

    /**

     * 刪除資料

     * @param key

     * @return

     */

    public boolean delete(int key) {

 

        Node current = root;

        while (current.next != null) {

            if(current.next.key == key) {

                current.next = current.next.next;

                return true;

            }

            current = current.next;

        }

        return false;

    }

 

    /**

     * 根據key獲取value

     * @param key

     * @return

     */

    public String get(int key) {

 

        Node current = root;

        while (current.next != null) {

            if(current.next.key == key) {

                return current.next.value;

            }

            current = current.next;

        }

        return null;

    }

 

    /**

     * 遍歷連結串列,列出所有資料

     * @return

     */

    public String list() {

 

        String str = "";

        Node current = root.next;

        while (current != null) {

            str += "(" + current.key + "," + current.value + "),";

            current = current.next;

        }

        return str;

    }

 

    @Override

    public String toString() {

        return list();

    }

}

```

 

MyHashMap

```

// 雜湊表

public class MyHashMap {

 

    // 連結串列陣列,陣列的每一項都是一個連結串列

    private MyLinkedList[] arr;

    // 陣列的大小

    private int maxSize;

 

    /**

     * 空參構造,預設陣列大小為10

     */

    public MyHashMap() {

        maxSize = 10;

        arr = new MyLinkedList[maxSize];

    }

 

    /**

     * 帶參構造,陣列大小自定義

     * @param maxSize

     */

    public MyHashMap(int maxSize) {

        this.maxSize = maxSize;

        arr = new MyLinkedList[maxSize];

    }

 

    /**

     * 新增資料,key值必須唯一

     * @param key

     * @param value

     */

    public void put(int key, String value) {

 

        int index = getHashIndex(key);

        if(arr[index] == null) {

            arr[index] = new MyLinkedList();

        }

        arr[index].add(key, value);

    }

 

    /**

     * 刪除資料

     * @param key

     * @return

     */

    public boolean delete(int key) {

 

        int index = getHashIndex(key);

        if(arr[index] != null) {

            return arr[index].delete(key);

        }

        return false;

    }

 

    /**

     * 根據key獲取value

     * @param key

     * @return

     */

    public String get(int key) {

 

        int index = getHashIndex(key);

        if(arr[index] != null) {

            return arr[index].get(key);

        }

        return null;

    }

 

    /**

     * 獲取陣列下標

     * @param key

     * @return

     */

    private int getHashIndex(Integer key) {

        return key.hashCode() % maxSize;

    }

 

    /**

     * 遍歷陣列中所有連結串列的資料

     * @return

     */

    public String list() {

 

        String str = "[ ";

        for (int i = 0; i < maxSize; i++) {

            if(arr[i] != null) {

                str += arr[i].toString();

            }

        }

        str = str.substring(0, str.length()-1);

        str += " ]";

        return str;

    }

 

    @Override

    public String toString() {

        return list();

    }

}

```

 

測試類

```

public class Test {

 

    public static void main(String[] args) {

 

        MyHashMap map = new MyHashMap(20);

 

        map.put(5, "aaa");

        map.put(8, "bbb");

        map.put(3, "ccc");

        map.put(8, "bbb");

        map.put(2, "ddd");

        map.put(9, "eee");

 

        System.out.println(map);

        System.out.println(map.get(3));

        System.out.println(map.delete(2));

        System.out.println(map);

    }

}

 


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69913892/viewspace-2658544/,如需轉載,請註明出處,否則將追究法律責任。

相關文章