Javascript 具有64位整数的哈希表

Javascript 具有64位整数的哈希表,javascript,node.js,Javascript,Node.js,我希望实现一个O(1)查找 我知道javascript没有真正的哈希表,而是使用对象和o(1)查找属性,但问题是键总是转换为字符串 我怀疑内存中有超过1000万个条目,如果我必须依赖字符串作为键,并且平均四键字符串为11.5个字符,这将等于(1000万个条目*11.5长度*2字节)=230000000字节或230MB 与存储为int64(1000万条*8字节)相比,8000000字节或80MB 我知道javascript本机不支持int64,但有一些库可以在执行我想要的逐位操作方面提供帮助 现在

我希望实现一个O(1)查找

我知道javascript没有真正的哈希表,而是使用对象和o(1)查找属性,但问题是键总是转换为字符串

我怀疑内存中有超过1000万个条目,如果我必须依赖字符串作为键,并且平均四键字符串为11.5个字符,这将等于(1000万个条目*11.5长度*2字节)=230000000字节或230MB

与存储为int64(1000万条*8字节)相比,8000000字节或80MB

我知道javascript本机不支持int64,但有一些库可以在执行我想要的逐位操作方面提供帮助

现在,尽管存在可以处理int64的库,但它们最终都不是真正表示8字节的对象,所以我认为我不能在哈希表中使用任何int64库,而是考虑使用两个int32的2深度哈希表。第一个键是前4个字节,第二个键是最后4个字节。它不像查找一个值的1次运算那样理想,但2次运算仍然足够好

但是,我觉得如果所有键都存储为字符串,或者所有数字都是双精度浮点格式的数字(8字节),那么每个哈希条目将占用16字节(两个“int32”数字),那么这就不值得了

我的问题是:

1.如果您存储一个数字作为属性的键,它会占用8吗 字节的内存,还是将其转换为字符串并占用 长度*2字节?

  • 有没有办法将二进制四键编码成双精度 javascript采用的浮点格式数字标准, 即使这个数字没有意义,底层的位也会服务于 目的(构造的唯一标识)
  • PS:我用nodejs标记这一点,因为可能存在可以帮助我实现最终目标的库


    编辑1:

    似乎1可以通过
    Map()
    和节点0.12.x实现+

    就number2而言,我能够使用int64库()并将64int转换为缓冲区

    我只想将缓冲区用作Map()的键,但它不允许我使用,因为缓冲区在内部是一个对象,每个实例都充当Map()的新键

    所以我考虑将缓冲区转换回原生类型,64位双精度

    使用
    readDoubleBE
    我将缓冲区读取为double,它表示我的64int二进制文件,并成功地让我在映射中使用它,并允许O(1)查找

    var ByteBuffer=require(“ByteBuffer”);
    var lookup=newmap();
    var startStr=“123123738232777”;
    
    对于(var i=1;i,因为您的键是整数(并且是唯一的),您可以将它们用作数组索引。但是,JS数组仅限于包含以32或64位整数为界的最大项,具体取决于您的平台

    为了克服这个问题,您可以使用两步方法,但不使用对象及其字符串散列
    store[0010][1000]=“VALUE”
    -具有二进制键
    00101000
    的项存储在第一个数组的索引
    0010
    下,索引
    1000
    存储在子数组中

    在十进制中,您处理的是
    store[2][8]='VALUE'
    ,这相当于在64位空间中执行
    store[40]='VALUE'

    您可以为自己创建一棵包含所有所需属性的树:

    • 您可以通过键轻松查找(分两步)
    • 你的键是整数
    • 您处理的是32位整数(或更少,取决于您如何对其进行分块)

    在您的node版本中,从
    Map
    Set
    的内存增加了一倍,这源于一个糟糕的实现。好吧,不是“坏”本身就是不适合数百万个条目。更简单的
    Set
    处理是用内存购买的。抱歉,一如既往,没有免费的午餐

    为什么他们通常使用这么多?他们应该处理任何对象,并且能够处理所有可能的种类的方法非常昂贵。如果你所有的都是一种类型,那么可以进行优化,但是你必须检查它,在99,99%的情况下,这不值得麻烦,因为地图、集合和数组都是short,最多几千条。平淡一点:开发人员的时间很昂贵,最好花在其他地方。我可以补充一句:这是开源的,自己动手吧!但我知道说起来容易做起来难;-)

    你需要自己滚。您可以为此使用
    uint32数组
    ,并围绕它构建一个哈希表

    Bing地图根据和使用以4位为基数(最多23位)的字符串进行编码。使用后者的编码(尚未读取前者,因此在细节中可能是错误的),我们可以将其转换为两个32位整数:

    function quadToInts(quad, zoom){
      var high,low, qlen, i, c;
      high = 0>>>0;
      low = 0>>>0
      zoom = zoom>>>0;
    
      // checks & balances omitted!
    
      qlen = quad.length;
    
      for(i = 0; i < 16 && i < qlen ;i++){
        c = parseInt(quad.charAt(i));
        high |= c << (32-(i*2 + 2));
      }
      // max = 23 characters (says MS)
      for(i = 0; i < 8 && i < qlen - 16 ;i++){
        c = parseInt(quad.charAt(16 + i));
        low |= c << (32-(i*2 + 2));
      }
    
      low |= zoom;
    
      return [high,low];
    }
    
    函数四元组(四元组,缩放){
    var高、低、qlen、i、c;
    高=0>>>0;
    低=0>>>0
    缩放=缩放>>>0;
    //省略了制衡!
    qlen=四元长度;
    对于(i=0;i<16&&i0;
    而((s>>=1)>0){
    掩码^=(掩码>>0;
    v=((v>>>s)和掩码)|((v>>0);
    }
    返回v;
    }
    函数intsToQuad(k1,k2){
    变量r、高、低、缩放、c、遮罩;
    r=“”;
    掩码=0x3;//0b11
    高=k1>>>0;
    低=k2>>>0;
    缩放=低&(0x20-1);
    低^=缩放;
    高=转速(高);
    对于(var i=0;i1)和掩码;
    r+=c.toString(10);
    高>>=2;
    }
    低=转速(低);
    对于(var i=0;i1)和掩码;
    r+=c.toString(10);
    低>>=2;
    }
    返回[r,缩放];
    }
    
    (所有快速黑客,请在使用前检查!C&p恶魔可能也在这里)

    基于以下哈希函数的哈希表的草图

    // shamelessly stolen from http://www.burtleburtle.net/bob/c/lookup3.c
    function hashword(k1, // high word of 64 bit value
                      k2, // low word of 64 bit value
                      seed // the seed
                      ){
    
      var a,b,c;
      var rot = function(x,k){
         return (((x)<<(k)) | ((x)>>>(32-(k))));
      };
    
      /* Set up the internal state */
      a = b = c = 0xdeadbeef + ((2<<2)>>>0) + seed>>>0;
    
      if(arguments.length === 2){
        seed = k1^k2;
      }
    
      b+=k2;
      a+=k1;
    
      c ^= b; c -= rot(b,14)>>>0;
      a ^= c; a -= rot(c,11)>>>0;
      b ^= a; b -= rot(a,25)>>>0;
      c ^= b; c -= rot(b,16)>>>0;
      a ^= c; a -= rot(c,4)>>>0; 
      b ^= a; b -= rot(a,14)>>>0;
      c ^= b; c -= rot(b,24)>>>0;
    
      return c;
    }
    function hashsize(N){
        var highbit = function(n) {
            var r = 0 >>> 0;
            var m = n >>> 0;
            while (m >>>= 1) {
                r++;
            }
            return r;
        };
    
      return (1<<(highbit(N)+1))>>>0;
    }
    function hashmask(N){
      return (hashsize(N)-1)>>>0;
    }
    
    //不知羞耻地从http://www.burtleburtle.net/bob/c/lookup3.c
    函数hashword(k1
    
    // obligatory https://graphics.stanford.edu/~seander/bithacks.html
    function rev(v){
      var s = 32;
      var mask = (~0)>>>0;         
      while ((s >>>= 1) > 0) {
        mask ^= (mask << s)>>>0;
        v = ((v >>> s) & mask) | ((v << s) & (~mask)>>>0);
      }
      return v;
    }
    
    function intsToQuad(k1,k2){
      var r, high, low, zoom, c, mask;
    
      r = "";
      mask = 0x3; // 0b11
    
      high = k1>>>0;
      low = k2>>>0;
      zoom = low & (0x20 - 1);
      low ^= zoom;
    
      high = rev(high);
      for(var i = 0;i<16;i++){
        c =  high & mask;
        c = (c<<1 | c>>>1) & mask;
        r += c.toString(10);
        high >>>= 2;
      }
      low = rev(low);
      for(var i = 0;i<16;i++){
        c =  low & mask;
        c = (c<<1 | c>>>1) & mask;
        r += c.toString(10);
        low >>>= 2;
      }
      return [r,zoom];
    }
    
    // shamelessly stolen from http://www.burtleburtle.net/bob/c/lookup3.c
    function hashword(k1, // high word of 64 bit value
                      k2, // low word of 64 bit value
                      seed // the seed
                      ){
    
      var a,b,c;
      var rot = function(x,k){
         return (((x)<<(k)) | ((x)>>>(32-(k))));
      };
    
      /* Set up the internal state */
      a = b = c = 0xdeadbeef + ((2<<2)>>>0) + seed>>>0;
    
      if(arguments.length === 2){
        seed = k1^k2;
      }
    
      b+=k2;
      a+=k1;
    
      c ^= b; c -= rot(b,14)>>>0;
      a ^= c; a -= rot(c,11)>>>0;
      b ^= a; b -= rot(a,25)>>>0;
      c ^= b; c -= rot(b,16)>>>0;
      a ^= c; a -= rot(c,4)>>>0; 
      b ^= a; b -= rot(a,14)>>>0;
      c ^= b; c -= rot(b,24)>>>0;
    
      return c;
    }
    function hashsize(N){
        var highbit = function(n) {
            var r = 0 >>> 0;
            var m = n >>> 0;
            while (m >>>= 1) {
                r++;
            }
            return r;
        };
    
      return (1<<(highbit(N)+1))>>>0;
    }
    function hashmask(N){
      return (hashsize(N)-1)>>>0;
    }
    
    /*
     Room for 8-byte (64-bit) entries
      Table pos.  Array pos.
       0             0         high, low
       1             2         high, low
       2             4         high, lowl
               ...
       n             n*2       high, low
    
    */
    function HashTable(N){
      var buf;
      if(!N)
        return null;
    
      N = (N+1) * 2;
    
      buf = new ArrayBuffer(hashsize(N) * 8);
      this.table = new Uint32Array(buf);
      this.mask = hashmask(N);
      this.length = this.table.length;
    }
    
    HashTable.prototype.set = function(s,z){
      var hash, quad, entry, check, i;
    
      entry = null;
      quad = quadToInts(s,z);
    
      hash = hashword(quad[0],quad[1]);
    
      entry = hash & this.mask;
    
      check = entry * 2;
      if(this.table[check] != 0 || this.table[check + 1] != 0){
        //handle collisions here
        console.log("collision in SET found")
        return null;
      } else {
        this.table[check] = quad[0];
        this.table[check + 1] = quad[1];
      }
      return entry;
    };
    
    HashTable.prototype.exists = function(s,z){
      var hash, quad, entry, check, i;
    
      entry = null;
      quad = quadToInts(s,z);
    
      hash = hashword(quad[0],quad[1]);
      entry = hash & this.mask;
    
      check = entry * 2;
      if(this.table[check] != 0 || this.table[check + 1] != 0){
    
        return entry;
      }
      return -1;
    };
    
    HashTable.prototype.get = function(index){
      var entry = [0,0];
    
      if(index > this.length)
        return null;
    
      entry[0] = this.table[index * 2];
      entry[1] = this.table[index * 2 + 1];
    
      return entry;
    };
    
    // short test
    var ht = new HashTable(100);
    ht.set("01231031020112310",17);
    ht.set("11231031020112311",12);
    ht.set("21231033020112310",1);
    ht.set("31231031220112311321312",23);
    
    var s = "";
    for(var i=0;i<ht.table.length;i+=2){
      if(ht.table[i] !== 0){
         var e = intsToQuad(ht.table[i],ht.table[i+1]);
         s += e[0] +", " +e[1] + "\n";
      }
    }
    console.log(s)