使用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