乍一看,这个任务似乎并不难:从源容器中获取唯一整数值的模数。首先想到的是将绝对值的所有内容转储到一个集合中并查看其大小:
#include <iostream>
#include <vector>
#include <set>
size_t getUniqueByModuleItemCount(const std::vector<int>& input)
{
std::set<unsigned> unique;
for(int item : input) {
unique.insert(abs(item));
}
return unique.size();
}
int main() {
std::vector<int> srcVec = {1, -4, 3, 2, -12, 0, 4, 17, -2, -2, -3, 13, 7};
size_t uniqueItemCount = getUniqueByModuleItemCount(srcVec);
std::cout << "Unique items count by absolute value is " << uniqueItemCount << std::endl;
}
它有效,但显然,这种算法的复杂性O(N*lnN)(通过原始容器的所有元素插入到树中,每次插入 lnN)。因此,问题是 - 是否有任何想法如何优化该算法的复杂性O(N)?
我做了一个小实验...
使用不同容器随机生成的
N具有正值和负值的数字向量:我们找出唯一元素的数量 1000 次。时间以微秒为单位,明明是正负……但还是挺适合评价的。我没有四舍五入,我觉得很容易在我的脑海里在几秒钟或几毫秒内算出来。
因此,向量开始丢失 10 到 10 万个哈希值。对于小值,散列甚至丢失
set'y,在 100 个元素的级别进行比较。然后set它无可救药地输给了所有人-据我了解,不仅是因为O(N*ln N),而且还因为大量的内存重新分配(reserve()它没有成员,不像散列和向量)。如何检查消耗的内存更简单,我没有想出什么,但很明显,这里 vector 会给大家一个良好的开端:)
一句话,最可悲的选择就是
set,根本就没有用的意思。对于小尺寸 - 高达数万 - 最好采用矢量,然后看看更重要的是什么 - 速度或内存。所有这些都在 Visual C++ 2015,32 位中。对于 Visual C++ 2010,32 位,vector 的优势就更加明显了 :) 而 hash 在这里丢失了:
谁想为其他编译器重复 - 不客气......
顺便说一下,您仍然可以使用向量进行优化——因为我们只需要唯一元素的数量——您不能
unique在内存中使用它进行混洗,而只是简单地遍历并重新计算那些邻居不相同的元素。更新。我假设匹配的数量很少;我在评论中被纠正了。我仍然没有使唯一元素的数量很少——手不会说谎——而是像这样填充数组:
那些。有很多巧合,但仍然是独特的元素——
O(N)2015年的成绩,没等到百万:
边界向下移动了一点,但原则仍然存在:
set飞过,但击败数组上的哈希值直到 100;hash 从 1000 开始领先,而不是从 10000 开始。在所有
N元素都是单位的极限下,结果几乎是自相矛盾的:矢量,而且只有矢量!这种情况下的散列甚至会丢失
set'y。一切,根本就没有时间做实验;谁想继续:)
Update2 - 在他的“优化的 C++”中,Günteroth 有充分的理由写道,
unordered_set虽然它产生了效果,但在阅读如何称赞它时,它根本不是人们所期望的 :) 书中的引述:哈希表std::unordered_map比 快std::map,但是不是由其声誉所暗示的数量级差异。