C++ 压缩字典具有非常快的int->;数据查找和快速反向查找(搜索/插入/删除数据)?

C++ 压缩字典具有非常快的int->;数据查找和快速反向查找(搜索/插入/删除数据)?,c++,algorithm,performance,dictionary,C++,Algorithm,Performance,Dictionary,我想实现一个字典,将唯一的异构数据(变量)与唯一的int配对,这样我就可以重复int,而不是重复值(可能很大)。需要时,我会通过字典将其转换为原始值 数据集很大,因此O(1)中的(int->data)很重要。(data->int)和insert/delete都应该是O(logn)average case,因为这些操作不太重要。数据的顺序无关紧要,但insert/delete不能使现有的int键失效 我尝试了哈希表和SSTable方法。对于哈希表,即使使用哈希值作为指示符,而不是将其与值一起存储,

我想实现一个字典,将唯一的异构数据(变量)与唯一的
int
配对,这样我就可以重复
int
,而不是重复值(可能很大)。需要时,我会通过字典将其转换为原始值

数据集很大,因此
O(1)
中的(int->data)很重要。(data->int)和insert/delete都应该是
O(logn)
average case,因为这些操作不太重要。数据的顺序无关紧要,但insert/delete不能使现有的int键失效

我尝试了哈希表SSTable方法。对于哈希表,即使使用哈希值作为指示符,而不是将其与值一起存储,所需的存储也相当高。碰撞降低了效率,但所有操作的摊销复杂性都是
O(1)
。另一方面,SSTable提供了更为复杂的操作,并复制了值(一次用于向量存储,一次用于映射索引)。总体内存消耗仅略低于哈希表字典

词典摘要中的要求:

  • 查找整型->数据:O(1)
  • 查找数据->最坏情况下的int:O(日志n)
  • 插入:最坏情况下为O(对数n)
  • 移除:最坏情况下为O(logn)[或者其他方式,如垃圾收集,如果不一直运行,可能会执行更差的操作]
  • 可能的最低内存要求

有没有一种方法可以改进字典的设计,以进一步减少内存需求,同时保留
O(1)
int->数据查找和合理的插入/删除/data->int?

您可以使用侵入式链表。例如:

struct Node {
    Node *prev, *next;
    variant<int, float, vector<string>> data;
};
现在,当您调用
delete node
时,它将从列表中消失


可以预见,Boost的实现具有许多奇特的特性:

您可以使用侵入式链表。例如:

struct Node {
    Node *prev, *next;
    variant<int, float, vector<string>> data;
};
现在,当您调用
delete node
时,它将从列表中消失


可以预见,Boost的实现具有许多奇特的特性:

如果
int
->数据速度是最重要的,那么您应该将其设置为一个数组索引操作

将数据对象保存在
std::vector forward\u映射中。int->data只是一个
正向映射[i]
查找,它是一个O(1),具有尽可能低的常数因子


使用单独的数据结构支持搜索/插入/删除操作。 根据“数据”对象支持的比较操作的不同,二叉搜索树或二叉树可能是不错的选择。BST/集合的“值”类型只是一个
int
,但是那些
int
s上的比较实际上是比较
forward\u map[i]
,而不是根据
i

因此,假设您有一个
std::无序集reverse\u map
。(使用STL容器实际上并不容易,请参见下文。)

实际上,我们使用集合作为映射:键是
向前映射[val]
,值是
int val
本身。

要查找给定
int k
的反向映射条目,您需要实际搜索它以查找
正向映射[k]

  • const data_t&lookup(int k){return forward_map[k];}

  • int搜索(常量数据&)
    反向映射。find()
    非常有效

  • 删除(常量数据&)
    :搜索并删除反向地图条目,返回
    int k
    。将
    k
    添加到前向映射的后进先出自由列表中。(不要触摸forward_map条目。如果需要检测forward_map条目释放后的使用情况,请在此点或其他位置将其归零。)
  • 插入(常量数据&)
    :检查自由列表的头部是否有可重复使用的条目,否则
    向前映射。向后推()
    k
    =您在前进地图中放置条目的位置。将
    k
    添加到反向映射
为避免存储另一份
数据\t
项,反向映射需要在其搜索操作中引用正向映射

由于缓存未命中,使用基于哈希表而不是搜索树的反向映射有一个潜在的巨大优势。通常,将键与树节点进行比较所需的所有数据都存在于节点中,但在本例中,它是对forward_map的引用。不仅可以从反向映射本身缓存未命中的加载,还可以向前映射[k]。(与无序CPU上的已知地址情况不同,来自未知地址的加载无法提前开始,因此这非常糟糕)。推测性执行可能会启动反向映射的下一次加载,但情况仍然很糟糕哈希表需要的总密钥比较要少得多,这是一个很大的优势


使用STL容器? 在这里使用STL容器有一个非常强的鸡和蛋问题<强>:考虑一个<代码> STD::unOrdEdEdSt< <代码>:键类型是“代码> int <代码>。我们将使用一个自定义的
KeyEqual
函数,该函数基于
forward\u map[i]
进行比较。但是只有
.find(const-Key&Key)
,而不是
.find(const-data&u-t&)

一个难看的解决方法是将
数据临时复制到
转发映射中的一个空闲槽中,这样它就有了一个索引,我们可以传递到
无序集::find
,但这种额外的复制是愚蠢的

另一个坏选项(可能不会在编译时进行优化)
是一个带有虚拟函数的类,用于访问
数据。地图上有一个带符号的类