Java實現的一個簡單HashMap(翻譯)

如何建立Hash表

對於把K(鍵)-V(值)這樣的鍵值對插入Hash表中,須要執行兩個步驟:java

  1. 使用散列函數將K轉換爲小整數(稱爲其哈希碼)。
  2. 哈希碼用於查找索引(hashCode%arrSize),而且首先搜索該索引處的整個鏈表(單獨鏈)以查找已存在的K。
  3. 若是找到,則更新其值,若是不是,則將K-V對存儲爲列表中的新節點。

複雜性和負載因子

  • 第一步,所用時間取決於K和散列函數。

例如,若是鍵是字符串「abcd」,那麼它的散列函數可能取決於字符串的長度。 可是對於很是大的n值,與n相比,映射中的條目數,密鑰的長度幾乎能夠忽略不計,所以能夠認爲散列計算在恆定時間內發生,即O(1)。node

  • 對於第二步,須要遍歷存在於該索引處的K-V對列表。 爲此,最壞的狀況多是全部n個條目都在相同的索引處。 所以,時間複雜度將是O(n)。 可是,已經進行了足夠的研究以使散列函數產生的鍵在數組中均勻分佈,所以這幾乎不會發生。
  • 所以,平均而言,若是有n個條目且b是數組的大小,則每一個索引上將有n / b個條目。 此值n / b稱爲負載因子,表示hash表上的負載狀況。
  • 該負載因子(Load Factor)須要保持較低,所以一個索引處的條目數較少,所以複雜度幾乎恆定,即O(1)。

Rehashing

顧名思義,rehashing意味着再次散列。 基本上,當負載因子增長到超過其預約值(負載因子的默認值爲0.75)時,複雜性就會增長。所以,爲了克服這個問題,數組的大小增長(加倍)而且全部值再次進行散列並存儲在新的雙倍大小的數組中,以保持低負載因子和低複雜度。數組

爲何要Rehashing

進行從新散列是由於每當將鍵值對插入到映射中時,負載因子增長,這意味着時間複雜度也如上所述地增長。 這可能沒法提供O(1)所需的時間複雜度。函數

所以,必須進行從新散列,增長Bucket Array的大小,以減小負載因子和時間複雜度。oop

如何Rehashing

能夠按以下方式進行Rehashing:ui

  • 對於每次向hash表添加新條目,請檢查負載因子。
  • 若是它大於其預約義值(若是沒有給出,則默認值爲0.75),而後從新散列。
  • 對於Rehashing,建立一個比之前大小加倍的新數組,並使其成爲新的Bucket Array。
  • 而後遍歷舊Bucket Array中的每一個元素,併爲每一個元素調用insert()函數,以便將其插入到新的更大的bucket數組中。

Java程序實例

// Java program to implement Rehashing 

import java.util.ArrayList; 

class Map<K, V> { 

    class MapNode<K, V> { 

        K key; 
        V value; 
        MapNode<K, V> next; 

        public MapNode(K key, V value) 
        { 
            this.key = key; 
            this.value = value; 
            next = null; 
        } 
    } 

    // The bucket array where 
    // the nodes containing K-V pairs are stored 
    ArrayList<MapNode<K, V> > buckets; 

    // No. of pairs stored - n 
    int size; 

    // Size of the bucketArray - b 
    int numBuckets; 

    // Default loadFactor 
    final double DEFAULT_LOAD_FACTOR = 0.75; 

    public Map() 
    { 
        numBuckets = 5; 

        buckets = new ArrayList<>(numBuckets); 

        for (int i = 0; i < numBuckets; i++) { 
            // Initialising to null 
            buckets.add(null); 
        } 
        System.out.println("HashMap created"); 
        System.out.println("Number of pairs in the Map: " + size); 
        System.out.println("Size of Map: " + numBuckets); 
        System.out.println("Default Load Factor : " + DEFAULT_LOAD_FACTOR + "\n"); 
    } 

    private int getBucketInd(K key) 
    { 

        // Using the inbuilt function from the object class 
        int hashCode = key.hashCode(); 

        // array index = hashCode%numBuckets 
        return (hashCode % numBuckets); 
    } 

    public void insert(K key, V value) 
    { 
        // Getting the index at which it needs to be inserted 
        int bucketInd = getBucketInd(key); 

        // The first node at that index 
        MapNode<K, V> head = buckets.get(bucketInd); 

        // First, loop through all the nodes present at that index 
        // to check if the key already exists 
        while (head != null) { 

            // If already present the value is updated 
            if (head.key.equals(key)) { 
                head.value = value; 
                return; 
            } 
            head = head.next; 
        } 

        // new node with the K and V 
        MapNode<K, V> newElementNode = new MapNode<K, V>(key, value); 

        // The head node at the index 
        head = buckets.get(bucketInd); 

        // the new node is inserted 
        // by making it the head 
        // and it's next is the previous head 
        newElementNode.next = head; 

        buckets.set(bucketInd, newElementNode); 

        System.out.println("Pair(" + key + ", " + value + ") inserted successfully.\n"); 

        // Incrementing size 
        // as new K-V pair is added to the map 
        size++; 

        // Load factor calculated 
        double loadFactor = (1.0 * size) / numBuckets; 

        System.out.println("Current Load factor = " + loadFactor); 

        // If the load factor is > 0.75, rehashing is done 
        if (loadFactor > DEFAULT_LOAD_FACTOR) { 
            System.out.println(loadFactor + " is greater than " + DEFAULT_LOAD_FACTOR); 
            System.out.println("Therefore Rehashing will be done.\n"); 

            // Rehash 
            rehash(); 

            System.out.println("New Size of Map: " + numBuckets + "\n"); 
        } 

        System.out.println("Number of pairs in the Map: " + size); 
        System.out.println("Size of Map: " + numBuckets + "\n"); 
    } 

    private void rehash() 
    { 

        System.out.println("\n***Rehashing Started***\n"); 

        // The present bucket list is made temp 
        ArrayList<MapNode<K, V> > temp = buckets; 

        // New bucketList of double the old size is created 
        buckets = new ArrayList<MapNode<K, V> >(2 * numBuckets); 

        for (int i = 0; i < 2 * numBuckets; i++) { 
            // Initialised to null 
            buckets.add(null); 
        } 
        // Now size is made zero 
        // and we loop through all the nodes in the original bucket list(temp) 
        // and insert it into the new list 
        size = 0; 
        numBuckets *= 2; 

        for (int i = 0; i < temp.size(); i++) { 

            // head of the chain at that index 
            MapNode<K, V> head = temp.get(i); 

            while (head != null) { 
                K key = head.key; 
                V val = head.value; 

                // calling the insert function for each node in temp 
                // as the new list is now the bucketArray 
                insert(key, val); 
                head = head.next; 
            } 
        } 

        System.out.println("\n***Rehashing Ended***\n"); 
    } 

    public void printMap() 
    { 

        // The present bucket list is made temp 
        ArrayList<MapNode<K, V> > temp = buckets; 

        System.out.println("Current HashMap:"); 
        // loop through all the nodes and print them 
        for (int i = 0; i < temp.size(); i++) { 

            // head of the chain at that index 
            MapNode<K, V> head = temp.get(i); 

            while (head != null) { 
                System.out.println("key = " + head.key + ", val = " + head.value); 

                head = head.next; 
            } 
        } 
        System.out.println(); 
    } 
} 

public class GFG { 

    public static void main(String[] args) 
    { 

        // Creating the Map 
        Map<Integer, String> map = new Map<Integer, String>(); 

        // Inserting elements 
        map.insert(1, "Geeks"); 
        map.printMap(); 

        map.insert(2, "forGeeks"); 
        map.printMap(); 

        map.insert(3, "A"); 
        map.printMap(); 

        map.insert(4, "Computer"); 
        map.printMap(); 

        map.insert(5, "Portal"); 
        map.printMap(); 
    } 
}

運行輸出

HashMap created
Number of pairs in the Map: 0
Size of Map: 5
Default Load Factor : 0.75

Pair(1, Geeks) inserted successfully.

Current Load factor = 0.2
Number of pairs in the Map: 1
Size of Map: 5

Current HashMap:
key = 1, val = Geeks

Pair(2, forGeeks) inserted successfully.

Current Load factor = 0.4
Number of pairs in the Map: 2
Size of Map: 5

Current HashMap:
key = 1, val = Geeks
key = 2, val = forGeeks

Pair(3, A) inserted successfully.

Current Load factor = 0.6
Number of pairs in the Map: 3
Size of Map: 5

Current HashMap:
key = 1, val = Geeks
key = 2, val = forGeeks
key = 3, val = A

Pair(4, Computer) inserted successfully.

Current Load factor = 0.8
0.8 is greater than 0.75
Therefore Rehashing will be done.


***Rehashing Started***

Pair(1, Geeks) inserted successfully.

Current Load factor = 0.1
Number of pairs in the Map: 1
Size of Map: 10

Pair(2, forGeeks) inserted successfully.

Current Load factor = 0.2
Number of pairs in the Map: 2
Size of Map: 10

Pair(3, A) inserted successfully.

Current Load factor = 0.3
Number of pairs in the Map: 3
Size of Map: 10

Pair(4, Computer) inserted successfully.

Current Load factor = 0.4
Number of pairs in the Map: 4
Size of Map: 10


***Rehashing Ended***

New Size of Map: 10

Number of pairs in the Map: 4
Size of Map: 10

Current HashMap:
key = 1, val = Geeks
key = 2, val = forGeeks
key = 3, val = A
key = 4, val = Computer

Pair(5, Portal) inserted successfully.

Current Load factor = 0.5
Number of pairs in the Map: 5
Size of Map: 10

Current HashMap:
key = 1, val = Geeks
key = 2, val = forGeeks
key = 3, val = A
key = 4, val = Computer
key = 5, val = Portal

原文連接this

相關文章
相關標籤/搜索