Java手写HashMap及拓展实践

Java手写HashMap

思维导图

HashMap
数组
链表
哈希函数

上述思维导图展示了Java手写HashMap的实现思路。HashMap是一种常用的数据结构,用于存储键值对。它的底层是由数组和链表组成的。数组用于存储数据,链表用于解决哈希冲突。在HashMap中,每个键值对通过哈希函数计算出一个哈希值,然后根据哈希值找到对应的数组位置,如果该位置已经有其他键值对存在,就使用链表将新的键值对添加到该位置的链表末尾。

实现步骤

1. 定义HashMap类

首先,我们需要定义一个HashMap类,用于存储键值对。

public class HashMap<K, V> {
    // 实现代码
}

2. 定义数组和链表

在HashMap类中,我们需要定义一个数组和一个链表。

private Node<K, V>[] table; // 数组
private static final int DEFAULT_CAPACITY = 16; // 默认数组大小

static class Node<K, V> {
    final K key;
    V value;
    Node<K, V> next;
    
    Node(K key, V value) {
        this.key = key;
        this.value = value;
    }
}

数组table用于存储键值对,链表Node用于解决哈希冲突。在链表中,每个节点包含一个键值对,以及指向下一个节点的指针。

3. 实现哈希函数

在HashMap中,我们需要实现一个哈希函数,用于计算键值对的哈希值。

private int hash(K key) {
    return key.hashCode() % table.length;
}

哈希函数使用hashCode()方法计算键值对的哈希值,然后使用取模运算将哈希值映射到数组的索引位置。

4. 实现put方法

接下来,我们需要实现put方法,用于向HashMap中添加键值对。

public void put(K key, V value) {
    int index = hash(key);
    Node<K, V> newNode = new Node<>(key, value);
    
    if (table[index] == null) {
        table[index] = newNode;
    } else {
        Node<K, V> current = table[index];
        while (current.next != null) {
            if (current.key.equals(key)) {
                current.value = value;
                return;
            }
            current = current.next;
        }
        current.next = newNode;
    }
}

put方法首先计算键值对的哈希值,然后根据哈希值找到对应的数组位置。如果该位置为空,则直接将新的节点添加到该位置。如果该位置已经有其他节点存在,则遍历链表,查找是否有相同的键。如果有相同的键,则更新对应的值,否则将新的节点添加到链表的末尾。

5. 实现get方法

我们还需要实现get方法,用于根据键获取对应的值。

public V get(K key) {
    int index = hash(key);
    
    if (table[index] == null) {
        return null;
    } else {
        Node<K, V> current = table[index];
        while (current != null) {
            if (current.key.equals(key)) {
                return current.value;
            }
            current = current.next;
        }
        return null;
    }
}

get方法首先计算键的哈希值,然后根据哈希值找到对应的数组位置。如果该位置为空,则返回null。如果该位置有节点存在,则遍历链表,查找是否有相同的键。如果找到相同的键,则返回对应的值,否则返回null

总结

通过手写HashMap的实现,我们加深了对HashMap的理解,并提高了编程能力。HashMap是一种常用的数据结构,它的底层是由数组和链表组成的,通过哈希函数将键值对映射到数组的索引位置,用链表解决哈希冲突。实现HashMap需要考虑哈希函数、数组和链表的操作,以及处理哈希冲突的方式。掌握HashMap的实现原理和实现步骤对于编程能力的提升是非常有帮助的。

拓展

除了基本的put和get操作,我们还可以实现其他功能,比如删除键值对、获取HashMap的大小等。删除键值对的操作比较简单,只需要找到对应的键,然后删除节点即可。获取HashMap的大小可以遍历数组,并统计每个位置的链表长度。另外,我们还可以实现自动扩容的功能,当HashMap中的键值对数量超过数组大小的75%时,自动扩容数组的大小。实现自动扩容需要创建一个新的更大的数组,并将原数组中的键值对重新计算哈希值,然后添加到新的数组中。

拓展实践

当HashMap中的键值对数量超过数组大小的75%时,我们可以通过自动扩容来提高HashMap的性能。下面是实现自动扩容的代码:

public void put(K key, V value) {
    int index = hash(key);
    Node<K, V> newNode = new Node<>(key, value);
    
    if (table[index] == null) {
        table[index] = newNode;
    } else {
        Node<K, V> current = table[index];
        while (current.next != null) {
            if (current.key.equals(key)) {
                current.value = value;
                return;
            }
            current = current.next;
        }
        current.next = newNode;
    }
    
    size++;
    
    if ((double) size / table.length > 0.75) {
        resize();
    }
}

private void resize() {
    int newCapacity = table.length * 2;
    Node<K, V>[] newTable = new Node[newCapacity];
    
    for (int i = 0; i < table.length; i++) {
        Node<K, V> current = table[i];
        while (current != null) {
            int newIndex = current.key.hashCode() % newCapacity;
            Node<K, V> newNode = new Node<>(current.key, current.value);
            
            if (newTable[newIndex] == null) {
                newTable[newIndex] = newNode;
            } else {
                Node<K, V> newCurrent = newTable[newIndex];
                while (newCurrent.next != null) {
                    newCurrent = newCurrent.next;
                }
                newCurrent.next = newNode;
            }
            
            current = current.next;
        }
    }
    
    table = newTable;
}

put方法中,我们首先判断当前HashMap的大小是否超过了数组大小的75%。如果是,则调用resize方法进行扩容。resize方法首先创建一个新的更大的数组newTable,然后遍历原数组table,将每个键值对重新计算哈希值,并添加到新的数组中。最后,将新的数组赋值给table

通过自动扩容,我们可以保证HashMap的性能在一定范围内。当HashMap中的键值对数量超过数组大小的75%时,我们将数组的大小扩大一倍,从而减少哈希冲突的概率,提高查找效率。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

竹山全栈

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值