如何有效地查找元素在一个大的向量

How to efficiently look up elements in a large vector

本文关键字:一个 向量 有效地 查找 元素      更新时间:2023-10-16

我有一个大小为(90,000 * 9,000)vector<unsigned>。我需要多次查找一个元素是否存在于这个向量中?

为此,我使用std::sort()以排序形式存储向量,然后使用std::binary_search()查找向量中的元素。然而,在使用perf进行分析时,我发现查找vector<unsigned>中的元素是最慢的操作。

有人可以建议一些C/C++中的data-structure,我可以用它来有效地查找(90,000 * 9,000)元素向量中的元素。

我只执行一次插入(大容量插入)。其余时间我只执行查找,所以这里的主要开销是查找。

您已经获得了40亿个可能值中的8.1亿个值(假设32位unsigned)。这是总范围的1/5,使用3.2 GB。这意味着你实际上更适合使用40亿比特的std::vector<bool>。这样可以在更少的空间(0.5 GB)内实现O(1)查找。

(理论上,unsigned可以是16位。unsigned long至少 32位,std::uint32_t可能是你想要的)

根据向量的实际数据结构,contains操作可以是O(n)O(1)。通常,如果vector由关联数组或链表支持,则为O(N),在这种情况下,contains在最坏的情况下将是完全扫描。您已经通过排序和使用二进制搜索(O(log (N)))减轻了完全扫描。Log N是相当好的复杂度,只有O(1)更好。所以你的选择是:

  • 缓存查找结果的项目,这可能是一个很好的妥协,如果你有许多重复的相同的元素
  • 将vector替换为其他具有高效contains操作的数据结构,例如基于散列表或集合的数据结构。注意,您可能会丢失其他功能,例如物品订购
  • 使用两种数据结构,一种用于contains操作,另一种用于
  • 的原始向量
  • 使用提供折衷的第三种数据结构,例如与布隆过滤器工作良好的数据结构

然而,在使用perf进行分析时,我发现在Vector是最慢的操作

这是你需要的一半信息,另一半是"与其他算法/容器相比,它有多快"?也许使用std::vector<>实际上是最快的,或者可能是最慢的。为了找到答案,你必须对几个不同的设计进行基准测试/配置文件。

例如,以下是在1000x9000大小的容器上使用随机整数的非常简单的基准测试(对于更大的映射,我可能会遇到段错误,假设是32位内存的限制)。

如果你需要一个非唯一整数的计数:

  • std::vector<unsigned> = 500 ms
  • std::map<unsigned, unsigned> = 1700 ms
  • std::unordered_map<unsigned, unsigned> = 3700 ms

如果您只需要测试是否存在唯一整数:

  • std::vector<bool> = 15 ms
  • std::bitset<> = 50 ms
  • std::set<unsigned> = 350 ms

请注意,我们对容器之间的相对比较不太感兴趣,而是对容器之间的确切值感兴趣。std::map<>相对较慢,考虑到动态分配的数量和所涉及的数据的非局部性,这并不奇怪。bitset是迄今为止最快的,但如果需要非唯一整数的计数,则不起作用。

我建议使用您确切的容器大小和内容进行类似的基准测试,这两者都可能影响基准测试的结果。std::vector<>可能是最好的解决方案,但现在你有一些数据来支持这个设计选择。

如果自c++11以来您不需要迭代集合(以排序的方式),您可以使用std::unordered_set<yourtype>,您需要做的就是为yourtype提供获取哈希和相等信息的集合方式。访问集合中元素的时间平摊为O(1),不像排序向量的时间是O(log(n))