Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/142.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 从庞大的列表中删除大量字符串_C++_Performance_List - Fatal编程技术网

C++ 从庞大的列表中删除大量字符串

C++ 从庞大的列表中删除大量字符串,c++,performance,list,C++,Performance,List,我在一个巨大的内存块中存储了大量字符串(通常有100k+甚至1M+)。这些实际上是散列,因此字符串的字母表限制为A-F0-9,每个字符串的长度正好为32字节(因此其存储的“压缩”)。从现在起,我将此列表称为主列表 我希望能够从主列表中删除项目。这通常是成批完成的,所以我会得到一个大的哈希列表(通常大约100到10k),我需要在这个列表中找到并删除它们。在这个操作结束时,大内存块中不能有任何空块,所以我需要考虑这一点。不能保证所有项目都会在主列表中,但没有一个项目会多次出现在主列表中。无法重新定位

我在一个巨大的内存块中存储了大量字符串(通常有100k+甚至1M+)。这些实际上是散列,因此字符串的字母表限制为A-F0-9,每个字符串的长度正好为32字节(因此其存储的“压缩”)。从现在起,我将此列表称为主列表

我希望能够从主列表中删除项目。这通常是成批完成的,所以我会得到一个大的哈希列表(通常大约100到10k),我需要在这个列表中找到并删除它们。在这个操作结束时,大内存块中不能有任何空块,所以我需要考虑这一点。不能保证所有项目都会在主列表中,但没有一个项目会多次出现在主列表中。无法重新定位,主块将始终保持相同大小

迭代主列表并检查是否应删除给定哈希值的天真方法当然有效,但有点慢。此外,小内存块的移动也有点过多,因为每次标记要删除的哈希时,我都会用主列表的最后一个元素重写它,从而满足没有空块的条件。当然,这会创建数千个小memcpy的,这反过来会使事情变得更慢,因为我会遇到大量的缓存未命中

有更好的方法吗?

一些重要注意事项:

  • 主列表没有排序,我不能浪费时间排序,这 是整个项目强加的限制,并重写它,以便 “列表始终排序”不是一个选项(甚至可能不是 (可能的)
  • 内存不是一个真正的问题,但是使用的越少越好
  • 我可以使用STL,但不能使用boost

    • 有两件事可能会有所帮助。首先,至少对项目列表进行排序 被移除;这样,就可以使用二进制搜索 (
      std::lower_bounds
      )。第二,保持两点: 源和目的地。如果来源指向某个东西 不在要删除的列表中,请将其复制到目标,然后 两者都要推进。如果源指向要删除的内容, 只需前进源指针,而不复制。应该有
      永远不要成为复制条目多次的理由

      好吧,如果我真的要优化它,我会这么做。 我假设顺序无关紧要,当你(IIUC)用最后一个项目交换项目来移除项目时,情况似乎就是这样

      • 存储128位整数(无论您如何表示它们,要么您的编译器以本机方式支持它们,要么您使用一个由32/64位整数组成的小数组),而不是32个字符字符串。见我对这个问题的评论
      • 滚动我自己的128位整数哈希集。请注意,如果你愿意想一想,做出一些假设,并认真对待,你可以在这里进行很多优化。一些注意事项:
        • 您只需要存储散列本身(用于冲突解决),以及一点或两点元数据来标识已删除/未使用的插槽。如果不确定如何保证正确性,请查看现有哈希表的功能。我认为,如果您只在构建哈希集之后删除(而不是添加),则更简单。虽然我认为,如果有一个值不是表示空插槽的有效哈希,甚至可以不使用该元数据,但这种方法更容易删除(只需翻转一点,而不是覆盖128位)
        • 您不需要散列函数,因为您的输入已经是整数了。你只需要做每一个哈希表都要做的事情:取模为2^n的哈希值,得到一个不是非常大的索引。选择n,使负载系数(使用的表项百分比)合理(<2/3似乎是标准值)。选择的幂次使模运算更便宜(通过二进制和屏蔽位),并允许您只在较低的32位或64位上执行(忽略其余部分)
        • 选择冲突解决策略很难。作为第一次尝试,我可能会选择线性探测。它可能工作得不好,但如果您的输入哈希是好的,这似乎不太可能。还有一个探测方案,它考虑到越来越多的你最初切断的比特,这些比特是由你使用的
      现在,与使用现成的解决方案相比,这是更多的工作和维护负担。我不会建议这样做,除非这真的像你描述的那样对性能至关重要。
      如果C++11是一个选项,并且您的编译器的
      无序集
      很好,那么您可能应该使用它,省去大部分麻烦(但请注意,这可能会增加内存需求)。您仍然需要专门化
      std::hash
      std::equal_to
      操作符==
      。您可以为
      无序集提供自己的
      散列
      键相等
      ,但这可能没有任何好处。

      您确定不值得对列表进行排序吗?对1百万个数据块(每个32字节)进行排序应该不会太难——而且它会将搜索要删除的数据块的O(n)算法更改为O(log2(n))——因此平均50万次搜索会变成平均20次搜索。这肯定值得吗?当然,假设这是您希望不止一次执行的操作,那么为什么要先存储字符串呢?32个十六进制数字可以存储在32*4=128位中,这将极大地减少内存消耗(并进一步提高缓存利用率和加速比较)。如果您绑定到基于字符串的API,您仍然可以(非常容易)在接收和请求字符串时进行转换。是否可以使用哈希集?与此暴力垃圾收集相比,您将“浪费”更少的时间对其进行排序,并使用更好的数据结构,无论其优化程度如何。我认为,如果不更好地理解项目所施加的约束,这将很难实现