当前位置:首页 > 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 方法实现 计算键的哈希值确定存储位置,处理哈希冲突后插入键值对。

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倍。

_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的幂次方,这样可以使用位运算代替取模运算提高效率:

js hasmap实现

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

标签: jshasmap
分享给朋友:

相关文章

vue.js实现轮播

vue.js实现轮播

Vue.js 实现轮播功能 使用第三方库(推荐) Vue.js 生态中有许多成熟的轮播组件库,例如 vue-awesome-swiper 或 swiper,它们功能丰富且易于集成。 安装 swipe…

js 实现继承

js 实现继承

原型链继承 通过让子类的原型对象指向父类的实例来实现继承。子类实例可以访问父类原型上的属性和方法。 function Parent() { this.name = 'parent'; } Par…

jquery js

jquery js

jQuery 简介 jQuery 是一个快速、简洁的 JavaScript 库,简化了 HTML 文档遍历、事件处理、动画和 Ajax 交互。它兼容多种浏览器,提供易于使用的 API,使开发者能够更高…

js实现百叶窗

js实现百叶窗

使用CSS和JavaScript实现百叶窗效果 通过CSS动画和JavaScript事件监听可以实现百叶窗效果。核心思路是将内容区域分割为多个条状元素,通过控制它们的展开/折叠状态来模拟百叶窗。…

js节流实现

js节流实现

节流的概念 节流(Throttle)是一种限制函数执行频率的技术,确保函数在一定时间间隔内只执行一次。常用于滚动事件、窗口调整等高频触发的场景。 基础实现方法 使用时间戳判断是否执行函数:…

js 实现递归

js 实现递归

递归的基本概念 递归是指函数直接或间接调用自身的过程。在JavaScript中,递归通常用于解决可以分解为相似子问题的问题,如阶乘、斐波那契数列、树形结构遍历等。 递归的实现要点 基线条件(Base…