数据流基本问题--独立元素计数(一)

来源:互联网 发布:ar制作软件 编辑:程序博客网 时间:2024/04/30 01:33

下面我们讨论如何计算独立元素数目。

一、问题定义

如果一个数据流,其中m为数据流的大小,。我们可以定义每个元素

出现的次数,其中为第i个元素出现的次数。假设,容易得知d为在

数据流中出现的不同元素数目,也就是独立元素数目。

对于这个问题,可以在内存中使用高效的搜索结构(比如平衡BST等)保留当前已经出现的元素。但是如果元素数目实在太

多以致搜索结构无法访问内存时,我们可以使用更多的机器或者将数据结构的一部分放入到外存中。

上述做法是计算流中独立元素的精确解。如果我们仅仅需要对独立元素数目进行估计,则方法要简单的多,空间消耗也很少

(一般确定性算法空间复杂度需要)。

二、具体算法

通过将流中元素哈希到一个足够长的位串,就可以实现独立元素数目的估计。这里要求哈希函数属于2-universal hash family。要求位串必须要足够长,以致哈希函数的可能结果数目要远大于流中独立元素个数。如果在流中看到的不同元素越多,我们看到的不同哈希值也就越多。对于一个元素哈希后的结果p,我们定义zero(p)为p的二进制表示尾部中连续0的个数。也就是如下定义:


如果我们记录流中所有元素zero()的最大值设为z,从直观上理解,如果流中独立元素数目越多,那么z的取值就会越大。算法的基本思想就是如果我们从d个不同的元素中希望有一个使得。举例来说,如果流中有8个独立元素,我们希望其中有一个满足哈希后的结果尾部有3个0。所以zero(h(j))的最大值(也就是下面算法中的z)理论上应该是log d的一个较好的近似。

基于上述想法,算法的步骤如下:

int get_distinct_elements_num(vector<int>&nums) {z=0;//h(i)为哈希函数//zero(i)是求i二进制表示尾部中连续0的数目for(int i=0;i<nums.size();i++){if(zero(h(nums[j]))>z){z=zero(h(nums[j]));}}return 2<<(z+1.0/2);}
三、算法的评估

假设为一个取值0或1的量,表示,t表示第二节中算法执行结束后z的取值。很明显,我们有:

或者

因为h(j)是取值是随机的,所以:


由于之间独立,我们得到的期望和方差:

(Var(x)表示x的方差,该步骤利用了)
     

分别由马尔科夫不等式和切比雪夫不等式可得:




是算法对d的估计,有。设a是满足的整数,b是满足的最大整数。则有


通过上面两个式子,可以发现,只是d的同阶的估计,并不是一个任意好的估计。另外,过大或者过小的概率并不是很大,只有

四、Median trick

所谓median trick就是我们运行这个算法k次,取k次结果的中位数即可。通过切尔诺夫界可以证明,median trick可以使过大或者过小的概率降低到足够低。直观上理解,取中位数的话就不会受到偶然极大值或者极小值的影响,从而是一个更好的估计。在后续的博客也会多次提及median trick。


五、附相关不等式。

1.马尔科夫不等式


2.切比雪夫不等式





2 0