面试题:手撕HashMap

看到这个题,不要被吓到了,不会难的咱还不会一个简单的吗?

我们实现的简单的HashMap命名为 MyHashMap ,先确定整体的设计:

  • 散列函数:hashCode()+除留余数法

  • 冲突解决:链地址法

定义一个内部节点:相当于链表。

class Node<K, V> {
        // 键值对
        private K key;
        private V value;

        // 链表
        private Node<K, V> next;

        public Node(K key, V value) {
            this.key = key;
            this.value = value;
        }

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

        public final V setValue(V newValue) {
            V oldValue = value;
            value = newValue;
            return oldValue;
        }

        public final K getKey() {
            return key;
        }

        public final V getValue() {
            return value;
        }
    }

主要有四个成员变量,其中桶数组作为装载数据元素的结构:

 //默认容量
    final int DEFAULT_CAPACITY = 16;
    //负载因子
    final float LOAD_FACTOR = 0.75f;
    //HashMap的大小
    private int size;
    //桶数组
    Node<K, V>[] buckets;

实现基础方法:

get :获取值

put :存入值

resize:扩容

    public MyHashMap() {
        size = 0;
        buckets = new Node[DEFAULT_CAPACITY];
    }

    public MyHashMap(int initCapacity) {
        size = 0;
        buckets = new Node[initCapacity];
    }

private int getIndex(K key, int length){
        int hash = hash(key);
        return Math.abs(hash) % length;
    }

    private int hash(K key) {
        int h = 0;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

    /**
     * put方法
     * @param key 键
     * @param value 值
     */
    public void put (K key, V value) {
        if (size >= buckets.length * LOAD_FACTOR) {
            resize();
        }
        putVal(key, value, buckets);
    }


    /**
     * 将元素存入指定的node数组
     *
     * @param key
     * @param value
     * @param table
     */
    private void putVal(K key, V value, Node<K, V>[] table) {
        int index = getIndex(key,table.length);
        Node<K,V> node  = table[index];
        // 待插入的位置为空
        if (node == null) {
            table[index] = new Node<>(key,value);
            size++;
            return;
        }
        // 待插入的位置不为空
        while (node.next != null) {
            //如果key相同,就覆盖掉
            if ((node.key.hashCode() == key.hashCode())
                    && (key == node.key || (node.key.equals(key)))) {
                node.value = value;
                return;
            }
            node = node.next;
        }
        // 插入到末尾
        node.next = new Node<>(key, value);
        size++;
    }

    /**
     * 扩容
     */
    private void resize() {
        //创建一个两倍容量的桶数组
        Node<K, V>[] newBuckets = new Node[buckets.length * 2];
        //将当前元素重新散列到新的桶数组
        rehash(newBuckets);
        buckets = newBuckets;

    }

    /**
     * 重新散列当前元素
     *
     * @param newBuckets 扩展后的桶
     */
    private void rehash(Node<K, V>[] newBuckets) {
        //map大小重新计算
        size = 0;
        //将旧的桶数组的元素全部刷到新的桶数组里
        for (int i = 0; i < buckets.length; i++) {
            //为空,跳过
            if (buckets[i] == null) {
                continue;
            }
            Node<K, V> node = buckets[i];
            while (node != null) {
                //将元素放入新数组
                putVal(node.key, node.value, newBuckets);
                node = node.next;
            }
        }
    }

测试

 public static void main(String[] args) {
        MyHashMap<String, String> map = new MyHashMap();
        for (int i = 0; i < 100; i++) {
            map.put("刘华强" + i, "你这瓜保熟吗?" + i);
        }
        System.out.println(map.size());
        for (int i = 0; i < 100; i++) {
            System.out.println(map.get("刘华强" + i));
        }


        map.put("刘华强1","哥们,你这瓜保熟吗?");
        map.put("刘华强1","你这瓜熟我肯定要啊!");
        System.out.println(map.get("刘华强1"));
    }

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

兜兜转转m

一毛钱助力博主实现愿望

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

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

打赏作者

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

抵扣说明:

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

余额充值