当前位置: 首页 > article >正文

面试经典-基于开放地址手写hashmap

一、解决Hash冲突的四种方式

由于哈希值的空间远小于输入的空间,所以经过散列处理后,仍然会出现不同的数据对应相同的数组下标,这时候就产生了哈希冲突。为了解决哈希冲突,有以下四种方法:

  1. 链式地址法:从发生冲突的那个单元起,按照一定的次序,从哈希表中重新找到一个空闲的位置。
  2. 开放地址法: 当发生地址冲突时,按照某种方法继续探测哈希表中的其他存储单元,直到找到空位置为止。
  3. 再哈希法: 就是同时构造多个不同的哈希函数,当发生冲突时,用另一个函数进行计算,直到冲突不再产生。
  4. 建立公共溢出区:将哈希表分为公共表和溢出表,当溢出发生时,将所有溢出数据统一放到溢出区。

二、源码中的应用

Java中的HashMap采用的是链式地址法,是一种寻址相对容易,插入也较容易的数据结构。
但是当数量不大,可用空间大,性能要求高,或者就要求数据线性排列,那么采用开放定址法会有优异的效果,实际上Python中的Dictionary、Java中ThreadLocal,就是使用开放寻址法解决冲突的。

三、代码

public class CustomMap {
    // 初始容量
    private static final int INITIAL_CAPACITY = 16;

    // 一维数组
    private Entry[] array;

    // 数组扩容阈值
    private int threshold;

    // 已使用空间
    private int usedSize = 0;

    class Entry {
        String key;
        Object value;

        Entry(String key, Object value) {
            this.key = key;
            this.value = value;
        }

        public String getKey() {
            return key;
        }

        public Object getValue() {
            return value;
        }
    }

    public LinearAddressMap(int capacity) {
        if (capacity == 0) {
            capacity = INITIAL_CAPACITY;
        }
        array = new Entry[capacity];
        setThreshold(capacity);
    }

    public void put(K key, V value) {
        if (key == null) {
            throw new IllegalArgumentException("key is null");
        }
        Entry[] internalArray = array;
        int len = internalArray.length;
        int i = key.hashCode() & (len - 1);
        Entry e = internalArray[i];

        if (e == null) {// 位置为空
            internalArray[i] = new Entry((String) key, value);
            updateUsedSpace();
            return;
        }

        if (e.getKey().equals(key)) {// key相等,替换旧值
            internalArray[i] = new Entry((String) key, value);
            return;
        }

        //出现hash冲突,从冲突位置开始,查找下一个空位置
        for (int index = i; index < len; index = nextIndex(index, len)) {
            if (internalArray[index] == null) {
                internalArray[index] = new Entry((String) key, value);
                break;
            }
        }
        updateUsedSpace();
    }

    private int nextIndex(int index, int len) {
        index++;
        return index % len;
    }

    public Object get(String key) {
        if (key == null) {
            throw new IllegalArgumentException("key is null");
        }
        int i = key.hashCode() & (array.length - 1);
        Entry e = array[i];
        if (e != null && e.getKey().equals(key)) {
            return e.getValue();
        } else {
            return getEntryAfterMiss(key, i, e);
        }
    }

    private Object getEntryAfterMiss(String key,int i,Entry e){
        Entry[] tab = array;
        int len = tab.length;
        while (e!= null){
            String k = e.getKey();
            if (k.equals(key)){
                return e.getValue();
            }else {
                i = nextIndex(i,len);
            }
            e = tab[i];
        }
        return null;
    }

    private void arrayResize(){
        Entry[] oldArray = array;
        int oldLen = oldArray.length;
        int newLen = oldLen * 2;
        Entry[] newArray = new Entry[newLen];
        int count = 0;
        for (int i = 0; i < oldLen; i++) {
            Entry e = oldArray[i];
            if (e != null){
                String k = e.getKey();
                int h = k.hashCode() & (newLen -1);
                while(newArray[h] != null){
                    h = nextIndex(h,newLen);
                }
                newArray[h] = e;
                count++;
            }
        }

        setThreshold(newLen);
        usedSize = count;
        array = newArray;
    }
}

http://www.kler.cn/a/273085.html

相关文章:

  • ES跟Kafka集成
  • 影刀RPA实战:嵌入python,如虎添翼
  • 【数据分享】1901-2023年我国省市县镇四级的逐年最高气温数据(免费获取/Shp/Excel格式)
  • IPC机制总结笔记
  • 建立maven项目常见问题解决办法
  • Oracle OCP认证考试考点详解082系列11
  • Elasticsearch使用Kibana进行基础操作
  • 基于springboot创建mybatis
  • 深度剖析:数字经济下人工智能水平的新测算模型数据集
  • 如何确保面试流程标准化操作,避免人为因素影响**
  • phpcms头像上传漏洞引发的故事
  • 字节跳动后端工程师实习生笔试题-c++
  • JavaWeb后端——分层解耦 IOC DI
  • GateWay路由规则
  • 阿里云-云服务器ECS新手如何建网站?
  • 每日五道java面试题之mybatis篇(一)
  • LeetCode 2882.删去重复的行
  • ubuntu安装docker的详细教程
  • 代码随想录 二叉树—平衡二叉树
  • 2023年度VSCode主题推荐(个人常用主题存档)
  • Machine Learning ---- Feature Scaling
  • 学完排序算法,终于知道用什么方法给监考完收上来的试卷排序……
  • VS2022 配置QT5.9.9
  • uniapp 兼容pc与手机的样式方法
  • hcia复习总结9
  • Custom GPTs Are Here and Will Impact Everything AI