高效的频率计数器

时间:2013-12-16 00:51:20

标签: c++ c++11 std

我有15,000,000 std:6个整数的向量。

这些15M载体包含重复。 重复的例子:

(4,3,2,0,4,23)
(4,3,2,0,4,23)

我需要获取一个具有相关计数的唯一序列列表。 (仅存在一次的序列将具有1个计数)

std C ++中有一个算法(可以是x11)一次性完成这个算法吗?

Windows,4GB RAM,30 + GB硬盘

3 个答案:

答案 0 :(得分:7)

标准库中没有这样的算法可以做到这一点,但是使用单个循环并选择正确的数据结构非常容易。

为此你想使用std::unordered_map,它通常是一个哈希映射。它预计每次访问的持续时间(插入和查找),因此是大数据集的首选。

以下访问和入侵技巧会自动在计数器地图中插入新条目(如果尚未存在);然后它会递增并回写计数。

typedef std::vector<int> VectorType;        // Please consider std::array<int,6>!

std::unordered_map<VectorType, int> counters;

for (VectorType vec : vectors) {
    counters[vec]++;
}

为了进一步处理,您很可能希望按出现次数对条目进行排序。为此,要么将它们写在对的向量中(它封装了数字向量和出现次数),要么在(有序的)映射中将其写入,其中键和值被交换,因此它由计数器自动排序。

为了减少此解决方案的内存占用,请尝试以下方法:

如果您不需要从此哈希映射中获取密钥,则可以使用不存储密钥但仅存储密钥的哈希映射。为此,使用size_t作为密钥类型,std::identity<std::size_t>作为内部哈希函数,并通过手动调用哈希函数std::hash<VectorType>来访问它。

std::unordered_map<std::size_t, int, std::identity<std::size_t> > counters;
std::hash<VectorType> hashFunc;

for (VectorType vec : vectors) {
    counters[hashFunc(vec)]++;
}

这会减少内存,但需要额外的努力来解释结果,因为你必须第二次遍历原始数据结构才能找到原始向量(然后通过再次散列它们在哈希映射中查找它们) )。

答案 1 :(得分:2)

是:首先std::sort列表(std::vector使用词典排序,第一个元素是最重要的),然后循环std::adjacent_find以查找重复项。找到重复项后,再次使用std::adjacent_find,但使用倒置比较器查找第一个 -duplicate。

或者,您可以将std::unique与自定义比较器一起使用,该比较器会在找到重复项时进行标记,并通过连续调用维护计数。这也为您提供了重复数据删除列表。

这些方法优于std::unordered_map的优点是空间复杂度与重复数量成正比。您不必复制整个原始数据集或添加一个很少使用的字段进行重复计数。

答案 2 :(得分:-1)

您应该将每个向量元素逐个转换为字符串,如“4,3,2,0,4,23”。 然后通过使用find()函数控制它们的存在,将它们添加到新的字符串向量中。

如果您需要原始矢量,请将字符串矢量转换为另一个整数序列矢量。 如果您在制作刺痛矢量时不需要删除重复的元素。