Javascript实现HashMap

使用Javascript简单实现HashMap结构, 使用Array作为桶列表, 自定义对象Entry作为链表节点

function HashMap() {

    var
        _this = (this instanceof HashMap) ? this : new HashMap(),
        _conf = {
            table: [],
            view: new EntryView(_this),
            modCount: 0,
            size: 0,
            MAX_LENGTH: 8,     // 记录桶的数量,
            loadFactor: 0.75,   // 负载因子,
            threshold: -1       // 计算何时增长
        },
        utils = {
            hash: function (s) {
                if (undefined === s)
                    throw new Error("Can't use undefined key");

                var hash = 0;
                if (!(s && s.length)) return hash;
                for (var i = 0; i < s.length; i++) {
                    var char = s.charCodeAt(i);
                    hash = ((hash << 5) - hash) + char;
                    hash = hash & hash; // Convert to 32bit integer
                }
                return hash;
            },
            indexFor: function (hash, len) {
                return hash % len;
            },
            addEntry: function (h, k, v, i) {
                if ((_conf.size >= _conf.threshold) && _conf.table[i]) {
                    _conf.MAX_LENGTH *= 2;
                    this.resize(_conf.MAX_LENGTH);

                    // TODO 为啥要rehash?
                    h = this.hash(k);
                    i = this.indexFor(h, _conf.MAX_LENGTH);
                }

                var oldBucket = _conf.table[i];
                var e = Entry(h, k, v, oldBucket);
                _conf.table[i] = e;
                _conf.view.add(e);
                _conf.size++;
            },
            resize: function (len) {
                var newTable = [];
                for (var index in _conf.table) {
                    var e = _conf.table[index];
                    while (e) {
                        e.hash = utils.hash(e.key);
                        var i = this.indexFor(e.hash, _conf.MAX_LENGTH);
                        var oldE = newTable[i];
                        newTable[i] = e;

                        // 遍历链表, 直至结束
                        var next = e.next;
                        e.next = oldE;
                        e = next;
                    }
                }

                if (len < newTable.length)
                    throw new Error("Invalid resize length:" + len);

                _conf.table = newTable;
                _conf.threshold = _conf.MAX_LENGTH * _conf.loadFactor;
            }
        };

    _conf.threshold = _conf.MAX_LENGTH * _conf.loadFactor;
    // if (debug)
    //     _this.conf = _conf;

    /**
     * 保存数据
     * @param k {String} 键
     * @param v {Object} 值
     * @return {Object} 返回键对应的原来的值, 如果没有返回null
     */
    this.put = function (k, v) {
        var
            h = utils.hash(k),
            i = utils.indexFor(h, _conf.MAX_LENGTH);
        for (var e = _conf.table[i]; e; e = e.next) {
            if (h == e.hash && k == e.key) {
                var oldV = e.value;
                e.value = v;
                return oldV;
            }
        }

        _conf.modCount++;
        utils.addEntry(h, k, v, i);
        return null;
    };

    /**
     * 获取数据
     * @param k {String} 关键字
     */
    this.get = function (k) {
        var
            h = utils.hash(k),
            i = utils.indexFor(h, _conf.MAX_LENGTH);
        for (var e = _conf.table[i]; e; e = e.next)
            if (e.hash == h && e.key == k)
                return e.value;
        return null;
    };

    /**
     * 删除指定键值对
     * @param k {String} 键
     * @return {object} 返回指定值, 如果没有返回null
     */
    this.remove = function (k) {
        var
            h = utils.hash(k),
            i = utils.indexFor(h, _conf.MAX_LENGTH),
            previous = null;
        for (var e = _conf.table[i]; e; e = e.next) {
            if (e.hash == h && e.key == k) {
                var
                    v = e.value,
                    next = e.next;

                if (previous)
                    previous.next = next;
                else
                    _conf.table[i] = next;

                _conf.view.del(e);
                _conf.size--;
                _conf.modCount++;

                return v;
            }
            previous = e;
        }
        return null
    };

    /**
     * 校验本次操作是否为安全的, 如果 modCount 与当前值不相同, 则认为不安全的
     * @param modCount {Number} 修改次数
     */
    this.isSafe = function (modCount) {
        if (modCount != _conf.modCount)
            throw new Error('Concurrent modification error');
    };

    /**
     * 获取当前集合大小
     * @return {number} 集合大小
     */
    this.size = function () {
        return _conf.size;
    };

    /**
     * 是否为空集合
     * @return {boolean} true-空集合, false-非空集合
     */
    this.isEmpty = function () {
        return !_conf.size;
    };

    /**
     * 清空集合数据
     */
    this.clear = function () {
        // _conf.table.splice(0, _conf.MAX_LENGTH);
        _conf.table = [];
        _conf.size = 0;
        _conf.view.clear();
        _conf.modCount++;
    };

    /**
     * 获取键列表, 要删除键值对需要调用
     * @see HashMap.remove()
     * @return {Array} 键列表
     */
    this.keySet = function () {
        return _conf.view.keys();
    };

    /**
     * 获取值列表
     * @return {Array} 值列表
     */
    this.values = function () {
        return _conf.view.values();
    };

    /**
     * 获取键值对列表,列表中每个元素可以调用 e.remove() 从 HashMap 中删除该键值对
     * @return {Array} 键值对列表
     */
    this.entrySet = function () {
        return _conf.view.entrySet(_conf.modCount);
    };
}


详情查看: http://git.oschina.net/osby/jstool/blob/master/src/map/HashMap.js


欢迎留言探讨!

你可能感兴趣的:(Javascript)