当前位置:首页 > JavaScript

js hasmap实现

2026-02-01 07:02:43JavaScript

HashMap 实现原理

HashMap 是基于哈希表的 Map 接口实现,允许使用 null 键和 null 值。它通过键的哈希码来存储数据,具有快速的访问速度。

核心组成部分

哈希函数 将键转换为数组索引的过程,通常使用键的 hashCode() 方法并结合扰动函数减少哈希冲突。

function hash(key) {
    let hashCode = 0;
    for (let i = 0; i < key.length; i++) {
        hashCode = (hashCode << 5) - hashCode + key.charCodeAt(i);
        hashCode |= 0; // Convert to 32-bit integer
    }
    return hashCode;
}

数组+链表/红黑树 哈希表底层是数组结构,每个数组元素称为桶(bucket)。当发生哈希冲突时,采用链表法解决冲突,当链表长度超过阈值时会转为红黑树。

基本操作实现

put 方法实现 计算键的哈希值确定存储位置,处理哈希冲突后插入键值对。

js hasmap实现

class HashMap {
    constructor(initialCapacity = 16, loadFactor = 0.75) {
        this.buckets = new Array(initialCapacity);
        this.loadFactor = loadFactor;
        this.size = 0;
    }

    put(key, value) {
        const index = this._getIndex(key);
        if (!this.buckets[index]) {
            this.buckets[index] = [];
        }

        const bucket = this.buckets[index];
        for (let i = 0; i < bucket.length; i++) {
            if (bucket[i].key === key) {
                bucket[i].value = value;
                return;
            }
        }

        bucket.push({ key, value });
        this.size++;

        if (this.size > this.buckets.length * this.loadFactor) {
            this._resize();
        }
    }
}

get 方法实现 通过哈希函数定位到对应桶,然后在链表或树中查找。

get(key) {
    const index = this._getIndex(key);
    const bucket = this.buckets[index];
    if (!bucket) return undefined;

    for (const entry of bucket) {
        if (entry.key === key) {
            return entry.value;
        }
    }
    return undefined;
}

扩容机制

当元素数量超过容量与负载因子的乘积时,进行扩容操作,通常扩大为原来的2倍。

js hasmap实现

_resize() {
    const newCapacity = this.buckets.length * 2;
    const newBuckets = new Array(newCapacity);

    for (const bucket of this.buckets) {
        if (!bucket) continue;
        for (const entry of bucket) {
            const newIndex = this._getIndex(entry.key, newCapacity);
            if (!newBuckets[newIndex]) {
                newBuckets[newIndex] = [];
            }
            newBuckets[newIndex].push(entry);
        }
    }

    this.buckets = newBuckets;
}

完整实现示例

class HashMap {
    constructor(initialCapacity = 16, loadFactor = 0.75) {
        this.buckets = new Array(initialCapacity);
        this.loadFactor = loadFactor;
        this.size = 0;
    }

    _hash(key) {
        let hashCode = 0;
        for (let i = 0; i < key.length; i++) {
            hashCode = (hashCode << 5) - hashCode + key.charCodeAt(i);
            hashCode |= 0;
        }
        return hashCode;
    }

    _getIndex(key, capacity = this.buckets.length) {
        return Math.abs(this._hash(key)) % capacity;
    }

    put(key, value) {
        const index = this._getIndex(key);
        if (!this.buckets[index]) {
            this.buckets[index] = [];
        }

        const bucket = this.buckets[index];
        for (let i = 0; i < bucket.length; i++) {
            if (bucket[i].key === key) {
                bucket[i].value = value;
                return;
            }
        }

        bucket.push({ key, value });
        this.size++;

        if (this.size > this.buckets.length * this.loadFactor) {
            this._resize();
        }
    }

    get(key) {
        const index = this._getIndex(key);
        const bucket = this.buckets[index];
        if (!bucket) return undefined;

        for (const entry of bucket) {
            if (entry.key === key) {
                return entry.value;
            }
        }
        return undefined;
    }

    _resize() {
        const newCapacity = this.buckets.length * 2;
        const newBuckets = new Array(newCapacity);

        for (const bucket of this.buckets) {
            if (!bucket) continue;
            for (const entry of bucket) {
                const newIndex = this._getIndex(entry.key, newCapacity);
                if (!newBuckets[newIndex]) {
                    newBuckets[newIndex] = [];
                }
                newBuckets[newIndex].push(entry);
            }
        }

        this.buckets = newBuckets;
    }
}

性能优化考虑

哈希冲突处理 当链表长度超过8时,可以考虑转换为红黑树,将查找时间复杂度从O(n)降为O(log n)。

哈希函数优化 使用更好的扰动函数减少哈希冲突,如Java HashMap中的高位运算:

_hash(key) {
    let h = 0;
    for (let i = 0; i < key.length; i++) {
        h = (h << 5) - h + key.charCodeAt(i);
        h ^= (h >>> 16); // 高位扰动
        h |= 0;
    }
    return h;
}

容量选择 初始容量最好选择2的幂次方,这样可以使用位运算代替取模运算提高效率:

_getIndex(key, capacity = this.buckets.length) {
    return this._hash(key) & (capacity - 1);
}

标签: jshasmap
分享给朋友:

相关文章

js实现图片上传

js实现图片上传

图片上传的基本实现 使用HTML的<input type="file">元素配合JavaScript的File API可以实现图片上传功能。HTML部分需要创建一个文件选择输入框和一个用于…

js实现日历

js实现日历

实现日历的基本思路 使用JavaScript实现日历的核心是动态生成日期表格,并处理月份切换逻辑。需要计算当前月的天数、起始星期几,并动态渲染到页面上。 获取当前日期信息 通过Date对象获取当前年…

js防抖和节流实现

js防抖和节流实现

防抖(Debounce)的实现 防抖的核心思想是在事件被触发后,延迟执行回调函数。如果在延迟时间内再次触发事件,则重新计时。适用于输入框搜索、窗口大小调整等场景。 function debounce…

js分组实现

js分组实现

分组实现方法 在JavaScript中,可以通过多种方式实现数组或对象的分组操作。以下是几种常见的方法: 使用Array.prototype.reduce() 通过reduce方法可以轻松实现数组分…

js实现论坛

js实现论坛

实现论坛的基本功能 使用JavaScript实现一个论坛需要结合前端和后端技术。前端可以使用React、Vue或Angular等框架,后端可以选择Node.js配合Express或Koa框架。数据库可…

js实现延迟

js实现延迟

实现延迟的方法 在JavaScript中,实现延迟操作有多种方式,以下是几种常见的方法: 使用setTimeout函数 setTimeout是JavaScript中最常用的延迟执行方法。它接受一个回…