基于滑动窗口DGIM算法实现

程序有一个输入参数:编写的程序维持一个大小为L 样本集合A(A是一个只能存储L个整数的数组),使得在任意第t>=L秒,当前窗口W^t中的元素以相等的概率被存储在A中(即被选取到A中)。所设计的程序对于所有的元素S=e(1),e(2),…,e(10 ^6),只能读取一遍,不能将整个中的元素都存在一个数组中在进行采样。

内容分析:程序对文件的采集数据量有10 ^6个数据,数据量非常庞大,但这些数据值相差不大并且分布均匀,因此可以采取数据样本均匀采集的方法使得数据等概率被采集到一个数组中,最后再对这些采集的数据进行处理,就不需要处理数据占用的内存了。此类问题的实际应用可能有大型web网站用来统计一段时间内独立用户数目,每次登录看成是一个流元素,我们可以用一个窗口维护最近一个月的所有登录用户的信息。无线摄像头图像数据信息的处理,图像流数据传回数据库时也可以采用此程序处理网络传回的字节图像流。等等。

算法设计-算法的思想:设立一个时间戳作为访问当前的数据的下标,设定一个数组作为滑动窗口由使用者设定大小并将所有采样数据全部存放在该数组中,然后开始遍历所有数据,随着时间戳增长超过数组时,由系统随机选取一个数作为下标t,若该数t未超过时间戳,则将当前的数据替换滑动窗口内的下标为t-1的样本数据,以此类推,直至采集到文件中的最后一个数据停止。

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

typedef struct
{
    int time_stamp;//时间戳
    int barrel_size;//桶的大小
}Barrel,*PBarrel;//桶的结构

int barrel_number;//限定相同大小桶的数目
int window_size;//给定滑动窗口大小
int t=0;//开始的时间戳为0
int time;//给定查询时刻
int barrel_count=0;//桶的个数且作为桶数组下标
void Barrel_combine(PBarrel barrel,int barrel_count);//声明函数
int Estimate_number(PBarrel barrel);
int Accurate_number(int *slip_window);

int main()
{
    int data;//接收数据流中0或1
    int e_num,a_num;//估计值和精确值
    PBarrel barrel;//桶的数组
    int *slip_window;//滑动窗口数组用于统计窗口内精确值
    float g;
    printf("输入限定相同大小桶的数目:");
    scanf("%d",&barrel_number);
    printf("输入滑动窗口的大小: ");
    scanf("%d",&window_size);
    printf("输入需要查询的时刻: ");
    scanf("%d",&time);
    barrel = (PBarrel)malloc(100 * sizeof(Barrel));
    slip_window = (int *)malloc(window_size * sizeof(int));
    FILE *fp=fopen("./01stream.txt","r");
    if(fp == NULL)
    {
        printf("open file falled!");
    }
    while(!feof(fp))
    {
        fscanf(fp,"%d\n",&data);
        t++;
        *(slip_window+(t%window_size)) = data;
        if(data == 1)
        {
            barrel[barrel_count].time_stamp = t;
            barrel[barrel_count].barrel_size = 1;
            Barrel_combine(barrel,barrel_count);
            barrel_count++;
        }
        if(t == time)
        {
            break;
        }
    }
    printf("桶的个数:  %d\n",barrel_count);
    for(int i=0;i<barrel_count;i++)
    {
        printf("桶的时间戳: %8d,    桶的大小: %4d\n",barrel[i].time_stamp,barrel[i].barrel_size);
    }
    e_num = Estimate_number(barrel);
    a_num = Accurate_number(slip_window);
    printf("估计值为 %d\t\t",e_num);
    printf("精确值为 %d\n",a_num);
    printf("误差为%.4f",(float)(abs(e_num-a_num))/(float)(a_num));
    fclose(fp);
    free(barrel);
    free(slip_window);
    return 0;
}

void Barrel_combine(PBarrel barrel,int n)
{
    int i,j,k;
    if(barrel[0].time_stamp<=(t-window_size))//判断时间戳有没有过期,过期则被后面的桶替换
    {
        for(i=0;i<n-1;i++)
        {
            barrel[i]=barrel[i+1];
        }
        barrel_count--;
        n--;
    }
    for(i=n;i>barrel_number-1;i--)
    {
        if(barrel[i].barrel_size ==  barrel[i-barrel_number].barrel_size)
        {
            barrel[i-barrel_number+1].barrel_size *= 2;
            barrel[i-barrel_number] = barrel[i-barrel_number+1];
            for(k=i-barrel_number+1;k<i;k++)
            {
                barrel[k]=barrel[k+1];
            }
            for(j=i;j<barrel_count;j++)
            {
                barrel[j]=barrel[j+1];
            }
            barrel_count--;
        }
    }
}

int Estimate_number(PBarrel barrel)
{
    int total=0;
    for(int i = barrel_count;i>0;i--)
    {
        total += barrel[i].barrel_size;
    }
    total += barrel[0].barrel_size/2;
    return total;
}

int Accurate_number(int *slip_window)
{
    int total=0,i;
    for(i=0;i<window_size;i++)
    {
        if(*(slip_window+i) == 1)
        {
            total++;
        }
    }
    return total;
}

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

风华绝代飞入鬓

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值