希望了解如何在JavaScript中实现哈希表in a decent way。
我希望它能够:
从我的研究和SO的帮助中,resolve collisions in hash tables有很多方法。 v8的方式是Quadratic probing:
在JavaScript中实现二次探测的wikipedia algorithm看起来像这样:
var i = 0
var SIZE = 10000
var key = getKey(arbitraryString)
var hash = key % SIZE
if (hashtable[hash]) {
while (i < SIZE) {
i++
hash = (key + i * i) % SIZE
if (!hashtable[hash]) break
if (i == SIZE) throw new Error('Hashtable full.')
}
hashtable[hash] = key
} else {
hashtable[hash] = key
}
维基百科条目中缺少的元素是:
getKey(arbitraryString)
。希望了解v8如何做到这一点(不一定是一个完全复制品,只是沿着相同的线)。不精通C,它看起来像key is an object和hash is a 32 bit integer。不确定lookup-cache.h是否重要。SIZE
约束。hash
的位置,以及如何多次计算。V8允许您指定自己的&#34; Shape&#34;要在哈希表中使用的对象:
// The hash table class is parameterized with a Shape.
// Shape must be a class with the following interface:
// class ExampleShape {
// public:
// // Tells whether key matches other.
// static bool IsMatch(Key key, Object* other);
// // Returns the hash value for key.
// static uint32_t Hash(Isolate* isolate, Key key);
// // Returns the hash value for object.
// static uint32_t HashForObject(Isolate* isolate, Object* object);
// // Convert key to an object.
// static inline Handle<Object> AsHandle(Isolate* isolate, Key key);
// // The prefix size indicates number of elements in the beginning
// // of the backing storage.
// static const int kPrefixSize = ..;
// // The Element size indicates number of elements per entry.
// static const int kEntrySize = ..;
// // Indicates whether IsMatch can deal with other being the_hole (a
// // deleted entry).
// static const bool kNeedsHoleCheck = ..;
// };
但不确定密钥是什么以及它们如何将该密钥转换为哈希值,因此密钥均匀分布,哈希函数不仅仅是一个hello-world示例。
问题是,如何实现像V8这样的快速哈希表,它可以有效地解决冲突,并且大小无限制。它不一定非常像V8,但具有上述功能。
就空间效率而言,一种天真的方法会做var array = new Array(10000)
,这会占用一大堆内存,直到它被填满。不确定v8如何处理它,但如果你多次var x = {}
,它不会为未使用的密钥分配一堆内存,不知何故它是动态的。
我基本上被困在这里:
var m = require('node-murmurhash')
function HashTable() {
this.array = new Array(10000)
}
HashTable.prototype.key = function(value){
// not sure if the key is actually this, or
// the final result computed from the .set function,
// and if so, how to store that.
return m(value)
}
HashTable.prototype.set = function(value){
var key = this.key(value)
var array = this.array
// not sure how to get rid of this constraint.
var SIZE = 10000
var hash = key % SIZE
var i = 0
if (array[hash]) {
while (i < SIZE) {
i++
hash = (key + i * i) % SIZE
if (!array[hash]) break
if (i == SIZE) throw new Error('Hashtable full.')
}
array[hash] = value
} else {
array[hash] = value
}
}
HashTable.prototype.get = function(index){
return this.array[index]
}
答案 0 :(得分:1)
这是一个非常广泛的问题,我不确定你到底想要什么答案。 (“如何实施......?”听起来你只是希望有人为你做你的工作。请更具体。)
如何计算哈希
任何哈希函数都可以。我已经在你提出的另一个问题中指出了V8的实现;但你真的有很多自由。
不确定lookup-cache.h是否重要。
不,这是无关的。
如何使其动态化,以便可以删除SIZE约束。
将表的当前大小存储为变量,跟踪哈希表中元素的数量,并在使用的槽的百分比超过给定阈值时增大表(在那里有一个时空权衡:负载较低)像50%这样的因素会减少碰撞,但会占用更多内存,80%的因素会占用更少的内存,但会遇到更慢的情况。我开始的容量是“你可能需要的最小条目数”的估计值,并且以2x(例如32-> 64-> 128->等)的步长增长。
存储最终哈希的位置
那个很难:在JavaScript中,你不能在字符串(或一般的原语)上存储其他属性。您可以在侧面使用Map
(或对象),但如果您打算这样做,那么您也可以将其用作 哈希表,而不是麻烦在顶层实施自己的事情。
以及如何多次计算它。
那个很容易:再次调用你的哈希函数; - )
我只想要一个函数
getUniqueString(string)
这个怎么样:
var table = new Map();
var max = 0;
function getUniqueString(string) {
var unique = table.get(string);
if (unique === undefined) {
unique = (++max).toString();
table.set(string, unique);
}
return unique;
}
对于更好的封装,您可以定义一个以table
和max
作为属性的对象。