DGIM算法能够使用O(log2N)位的情况下表示N位窗口,将估计得错误率降到任意大于0得数。
流中每位都有时间戳,我们将窗口划分为多个桶,每个桶中包含
1、最右部得时间戳(最近的时间戳)
2、桶的大小(桶中1的个数,是2的幂)
此时桶必须遵循6条规则:
1、桶的最右部的位置总是1;
2、每个1的位置都在桶内、
3、一个位置只能属于一个桶
4、桶的大小从小到大,相同的桶的个数只有一到r个
5、从远到近扫描,桶的大小不会减少
算法过程,每次流中来1的时候,新建一个大小为1的桶,当相同桶的个数达到r+1个的时候,将最前面两个桶合为一个桶,并把过期的桶删除(时间戳大于当前时间-窗口大小)。当我要输出某时刻当前窗口1的个数,即将最早的桶的大小*50%+后面每个桶的大小。
此时误差:假设最左边桶的大小为2的j次(后面用2j代替吧),真实的至少为1+(r-1)(2的j-1次+2的j-2次+。。。+1)=(r-1)(2j - 1)。
最大误差: (2的j-1次-1)/(1+(r-1)(2的j次-1))
c语言实现,建立双向循环链表,用来存储桶
#include <iostream> #include <cstdio> #include <cstdlib> #define MaxSize 100010 using namespace std; typedef struct node { int bsize; int btime; struct node *next; struct node *pior; }Bucket,*pBucket; void addItem(pBucket h,int t) //添加新的桶 { pBucket p; p=(pBucket)malloc(sizeof(Bucket)); p->bsize=1; p->btime=t; p->next=h; p->pior=h->pior; h->pior->next=p; h->pior=p; } void Delete(pBucket h,int t,int size_win) //删除过期桶 { pBucket p; while(1) { p=h->next; if(p->btime<(t-size_win)) { h->next=p->next; p->next->pior=h; free(p); } else break; } } void Merge(pBucket h,int max_num ) //合并 { int i,t,size,same; pBucket p,q; q=h->pior; while(q!=h) { same=1; p=q; for(i=1;i<=max_num;i++) { if(p->pior->bsize!=p->bsize || p->pior==h) { same=0; break; } p=p->pior; } if(same==1) { for(i=0;i<max_num;i++) //找到要合并的桶 { q=q->pior; } p=q->next; //找到要删除的桶 t=p->btime; size=(p->bsize)*2; p->pior->next=p->next; p->next->pior=p->pior; free(p); /* for(i=1;i<max_num;i++) { p=q->pior; p->pior->next=p->next; p->next->pior=p->pior; free(p); } */ q->bsize=size; q->btime=t; } else break; } } int Print_estimate(pBucket h,int max_num) { pBucket p; int total_num=0; p=h->next; total_num+=p->bsize*(1.0/max_num); printf("size : %d, time:%d\n",p->bsize,p->btime); p=p->next; while(p!=h) { printf("size : %d, time:%d\n",p->bsize,p->btime); total_num+=p->bsize; p=p->next; } printf("estimate total: %d\n",total_num); return total_num; } int Prin_real(int window[],int size_win) { int i,num=0; for(i=0;i<size_win;i++) num+=window[i]; printf("real total:%d\n",num); return num; } int main() { FILE *fp; int temp;//临时变量,用来记录该时刻的数集,1或0 int t_now=0,t_need,max_num_buc; int window[MaxSize]={0},size_win; int est_num,real_num; pBucket Buc; Buc=(pBucket)malloc(sizeof(Bucket)); Buc->next=Buc; Buc->pior=Buc; //头指针初始化 if(!(fp=fopen(".\\01stream.txt","r"))) printf("FAIL TO OPEN FILE"); printf("请输入滑动窗口大小:\n"); scanf("%d",&size_win); printf("请输入想获取数据的时间:\n"); scanf("%d",&t_need); printf("请输入精度:\n"); scanf("%d",&max_num_buc); while(fscanf(fp,"%d",&temp)!=EOF && t_need!=t_now) { window[t_now%size_win]=temp; if(temp==1) { addItem(Buc,t_now);//新建一个桶; Delete(Buc,t_now,size_win); Merge(Buc,max_num_buc ); } t_now++; } fclose(fp); est_num=Print_estimate(Buc,max_num_buc); real_num=Prin_real(window,size_win); printf("误差:%f\n",(float)(est_num-real_num)/(float)real_num); return 0; }