如何实现像v8

时间:2018-01-09 01:35:34

标签: javascript data-structures hash hashtable v8

希望了解如何在JavaScript中实现哈希表in a decent way

我希望它能够:

  1. 有效解决冲突
  2. 节省空间
  3. 大小无限(至少在原则上,就像v8对象一样,最大可达系统内存的大小)。
  4. 从我的研究和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
    }
    

    维基百科条目中缺少的元素是:

    1. 如何计算哈希getKey(arbitraryString)。希望了解v8如何做到这一点(不一定是一个完全复制品,只是沿着相同的线)。不精通C,它看起来像key is an objecthash is a 32 bit integer。不确定lookup-cache.h是否重要。
    2. 如何使其动态化,以便可以删除SIZE约束。
    3. 存储最终hash的位置,以及如何多次计算。
    4. 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]
      }
      

1 个答案:

答案 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;
}

对于更好的封装,您可以定义一个以tablemax作为属性的对象。