C++ 如何在通过数组的一次过程中近似计算数组中不同值的计数
我有几个巨大的数组(数百万个++成员)。所有这些都是数字数组,它们没有排序(我不能这样做)。有些是C++ 如何在通过数组的一次过程中近似计算数组中不同值的计数,c++,arrays,algorithm,search,C++,Arrays,Algorithm,Search,我有几个巨大的数组(数百万个++成员)。所有这些都是数字数组,它们没有排序(我不能这样做)。有些是uint8\u t,有些是uint16\u t/32/64。我想大致计算这些数组中不同值的计数。条件如下: 速度非常重要,我需要在一个数组中完成这一点,并且必须顺序地通过它(不能来回跳)(我在C++中做这件事,如果这很重要) 我不需要精确的计数。我想知道的是,如果它是一个uint32_t数组,如果有10或20个不同的数字,或者如果有数千或数百万 我有相当多的内存可以使用,但使用的越少越好 数组数据类
uint8\u t
,有些是uint16\u t/32/64
。我想大致计算这些数组中不同值的计数。条件如下:
ArrayA [uint32_t, 3M members]: ~128 distinct values
ArrayB [uint32_t, 9M members]: 100000+ distinct values
ArrayC [uint8_t, 50K members]: 2-5 distinct values
ArrayD [uint8_t, 700K members]: 64+ distinct values
我理解有些限制似乎不合逻辑,但事实就是这样。
作为旁注,我还想要使用最多和最少的前X(3或10)值,但这要容易得多,我可以自己做。然而,如果有人也有这样的想法,请随意分享
编辑:关于STL的一点澄清。如果您有使用它的解决方案,请发布它。不使用STL对我们来说只是一种奖励,我们不太喜欢它。然而,如果这是一个好的解决方案,它将被使用 对于8位和16位的值,您只需制作一个每个值的计数表;每次写入以前为零的表条目时,都会发现一个不同的值
对于较大的值,如果您对100000以上的计数不感兴趣,
std::map
是合适的,只要它足够快。如果这对您来说太慢,您可以编写自己的B-树。我很确定您可以通过以下方式完成:
因此,我可能遗漏了一些内容,但我认为在最坏的情况下,“最常用”的问题要求您为所看到的每个值保留一个计数,直到数组的末尾。因此,您也可以使用该计数集合计算出有多少个不同的值。一种即使对于较大的值也有效的方法是将它们分散到延迟分配的存储桶中 假设您使用的是
32
位整数,创建2**32
位数组相对来说是不切实际的(2**29
字节,哼哼)。但是,我们可以假设2**16
指针仍然合理(2**19
字节:500kB),因此我们创建2**16
存储桶(空指针)
因此,最重要的想法是采用“稀疏”方法进行计数,并希望整数不会分散,因此许多桶指针将保持null
typedef std::pair<int32_t, int32_t> Pair;
typedef std::vector<Pair> Bucket;
typedef std::vector<Bucket*> Vector;
struct Comparator {
bool operator()(Pair const& left, Pair const& right) const {
return left.first < right.first;
}
};
void add(Bucket& v, int32_t value) {
Pair const pair(value, 1);
Vector::iterator it = std::lower_bound(v.begin(), v.end(), pair, Compare());
if (it == v.end() or it->first > value) {
v.insert(it, pair);
return;
}
it->second += 1;
}
void gather(Vector& v, int32_t const* begin, int32_t const* end) {
for (; begin != end; ++begin) {
uint16_t const index = *begin >> 16;
Bucket*& bucket = v[index];
if (bucket == 0) { bucket = new Bucket(); }
add(*bucket, *begin);
}
}
typedef std::pair对;
typedef std::向量桶;
typedef std::向量;
结构比较器{
布尔运算符()(成对常数和左、成对常数和右)常数{
返回left.firstfirst>值){
v、 插入(它,成对);
返回;
}
它->秒+=1;
}
无效聚集(向量和向量、int32_t常量*开始、int32_t常量*结束){
for(;begin!=end;++begin){
uint16_t const index=*begin>>16;
Bucket*&Bucket=v[索引];
如果(bucket==0){bucket=new bucket();}
添加(*桶,*开始);
}
}
一旦你收集了数据,你就可以很容易地计算出不同值的数量,或者找到顶部或底部
请注意:
- 桶的数量完全是custo
-- number of distinct SELECT COUNT(DISTINCT(n)) FROM @tmp -- top x SELECT TOP 10 n, COUNT(n) FROM @tmp GROUP BY n ORDER BY COUNT(n) DESC