Javascript 从整数到整数的高效稀疏映射

Javascript 从整数到整数的高效稀疏映射,javascript,Javascript,我正在使用有限自动机实现一个专门构建的正则表达式引擎。我必须存储数千个州,每个州都有自己的从unicode代码点(或UTF-16代码单元;我还没有决定)到州ID的转换表 在许多情况下,表将非常稀疏,但在其他情况下,它将几乎是满的。在大多数情况下,大多数条目将落入几个具有相同值的连续范围 最简单的实现是查找表,但每个这样的表都会占用大量空间。(范围、值)对的列表将小得多,但速度较慢。二叉搜索树将比列表更快 是否有更好的方法,也许是利用内置功能?听起来您有两种截然不同的情况(“在许多情况下,表将非常

我正在使用有限自动机实现一个专门构建的正则表达式引擎。我必须存储数千个州,每个州都有自己的从unicode代码点(或UTF-16代码单元;我还没有决定)到州ID的转换表

在许多情况下,表将非常稀疏,但在其他情况下,它将几乎是满的。在大多数情况下,大多数条目将落入几个具有相同值的连续范围

最简单的实现是查找表,但每个这样的表都会占用大量空间。(范围、值)对的列表将小得多,但速度较慢。二叉搜索树将比列表更快


是否有更好的方法,也许是利用内置功能?

听起来您有两种截然不同的情况(“在许多情况下,表将非常稀疏,但在其他情况下,表将几乎满”)

对于稀疏情况,您可能有一个单独的稀疏索引(或几层索引),然后您的实际数据可以存储在一个类型化数组中。因为索引将从整数映射到整数,所以它们也可以表示为类型化数组

查找值的方式如下所示:

  • 二进制搜索索引。索引将对作为连续项存储在类型化数组中–第一个元素是搜索值,第二个元素是数据集中的位置(或下一个索引)
  • 如果有多个索引,请根据需要重复1
  • 在最后一个索引给定的位置开始迭代数据集。因为索引是稀疏的,所以这个位置可能不是存储值的位置,但它是一个很好的起点,因为可以保证正确的值在附近
  • 数据集本身被表示为一个类型化数组,其中连续的对包含键和值
  • 我想不出有什么比JavaScript更好的了。类型化数组速度非常快,具有索引应该会大大提高速度。这就是说,如果您只有几千个条目,不用麻烦索引,直接在类型化数组上进行二进制搜索(如上面4.所述)


    对于密集的情况,我不确定。如果密集的情况正好是一个重复键值范围的情况,那么考虑使用类似的东西——简单的相同的连续值被简单地表示为它们的出现次数,然后表示实际值。再一次,使用类型化数组和二进制搜索,甚至可能使用索引来加快搜索速度。

    不幸的是,JavaScript的内置数据类型——特别是
    Map
    ——对完成这项任务没有太大帮助,因为它们缺乏相关的方法

    在大多数情况下,大多数条目将分为几个连续的条目 具有相同值的范围

    不过,我们可以利用这一点,并在排序数组上使用二进制搜索策略,前提是转换表不会经常修改

    通过在排序数组中存储每个输入范围的最低值,对导致相同状态的连续输入范围进行编码。将相应索引处的状态保留在单独的数组中:

    let inputs = [0, 5, 10]; // Input ranges [0,4], [5,9], [10,∞)
    let states = [0, 1, 0 ]; // Inputs [0,4] lead to state 0, [5,9] to 1, [10,∞) to 0
    
    现在,给定一个输入,您需要对输入数组执行二进制搜索,类似于:

    //返回小于或等于的最大元素的索引
    //给定元素,如果没有此类元素,则为未定义元素:
    功能floorIndex(已排序,元素){
    设low=0;
    设high=sorted.length-1;
    而(低)>1;
    if(已排序的[mid]>元素){
    高=中-1;
    }else if(已排序[中间]<元素){
    低=中+1;
    }否则{
    中途返回
    }
    }
    返回低-1;
    }
    //示例:1F600-1F64F范围内的表情符号转换为1:
    让变换={
    输入:[0x00000、0x1F600、0x1F650],
    国家:[0,1,0]
    };
    
    让输入=0x1F60B;//自(现代)javascript数组本身是稀疏的,这不应该是内存问题;许多数组元素也可以引用同一个对象,这将在遇到范围时为您节省一些空间。@StephenP问题是关于映射到整数。您必须包装整数才能引用它们(因为它们是基元类型),所以引用实际上会慢一些