【问题标题】:Reservoir Sampling algorithm not wroking水库采样算法不起作用
【发布时间】:2014-12-23 20:32:43
【问题描述】:

我的数据挖掘课程有一个项目,我必须在其中编写文件的水库采样算法。该程序将数字 k、输入文件的名称和要创建的输出文件的名称作为输入。输出文件必须包含来自输​​入的 k 个随机行。我尝试了一些东西,但输出错误。

这是我使用的代码:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>

int countLines(FILE* file)
{
    char ch,lines=0;

    while ((ch=fgetc(file)) != EOF)
        if (ch=='\n')
            lines++;
    return(lines);
}

void itemSelection(FILE* fp1, FILE* fp2, int k)
{
    int i,j,n,test=0;
    char line[256];
    char** buffer;

    srand((unsigned int) time(NULL));
    buffer = (char**)malloc(sizeof(char*));
    for(i=0;i<k;i++)
        buffer[i] = (char*)malloc(256*sizeof(char));
    n = countLines(fp1);
    if(k>n)
    {
        rewind(fp1);
        while(fgets(line, 256, fp1)!=NULL)
        {
            printf("%s test\n",line); 
            fprintf(fp2,"%s",line); 
        }
    }
    else
    {
        rewind(fp1);    
        for(i=0;i<k;i++)
        {
            fgets(line, 256, fp1);
            buffer[i]=line;
            printf("first k lines:\t%s\n",buffer[i]);
        }
        for(i=k;i<n;i++)
        {
            fgets(line,256,fp1);
            printf("line is:\t%s.\n", line);
            j = rand() % (i+1);
            if(j<k)
            {
                buffer[j]=line;
                printf("later parts are:\t%s. J is:%d.\n",buffer[j],j);
            }
        }
    }
    for(i=0;i<k;i++)
        printf("buffer test:\t%s.\n", buffer[i]);
}

void printFunc(FILE* fp2,int k)
{
    char line[256];
    int i;

    rewind(fp2);
    for(i=0;i<k;i++)
    {
        fgets(line, 256, fp2);
        printf("print test is:\t%s.\n",line);
    }   
}

void main(int args, char** argv)
{
    FILE* fp1;
    FILE* fp2;
    int k;

    if(args<4)
    {
        printf("Expected more arguments!\n");
        exit(-1);
    }

    fp1 = fopen(argv[2],"r");
    if(fp1 == NULL)
    {
        printf("Could not open input file!\n");
        perror("Error: ");
        exit(-1);
    }
    fp2 = fopen(argv[3],"w");
    if(fp2 == NULL)
    {
        printf("Could not open output file!\n");
        perror("Error: ");
        exit(-1);
    }
    k = atoi(argv[1]);
    itemSelection(fp1, fp2, k);
    printFunc(fp2,k);
    fclose(fp1);
    fclose(fp2);
}

这个程序试图做的是从文件中读取前 k 行并将其存储在 (k,256) 大小的二维字符串数组中。然后为下一行生成一个随机数 j,如果该数小于 k,则将 buffer[j] 替换为从文件中获取的最新行。

但是我得到的输出由 k 行 } 组成,这是输入的最后一个字符。 像这样(例如 k=5):

}
}
}
}
}

当我打印缓冲区以查看其内容时,它会正确显示。但是当我写入文件时,它会写入错误的输出。

任何帮助将不胜感激!提前谢谢!

【问题讨论】:

    标签: c algorithm data-mining sampling reservoir-sampling


    【解决方案1】:

    选择行时,必须复制行的内容,而不是指针(始终为line,其内容将不断被覆盖):

    buffer[i]=line;
    

    应该是

    strcpy(buffer[i], line);
    

    buffer[j] 也是如此。

    你也有分配错误:

    buffer = (char**)malloc(sizeof(char*));
    

    应该是:

    buffer = malloc(k * sizeof(char*));
    

    k 字符串腾出空间(并听取有关casting the result of malloc in C 的流行建议)。你还应该考虑一下你想用buffer做什么:你是返回它,以便客户端代码可以使用它(并且必须free它)还是它是itemSelection本地的,应该free在返回之前。目前你两者都不做。

    最后,在您的countLines 函数中,变量应该是int,而不是charfgetc 返回一个整数,因此您可以区分所有有效(无符号)char 值和特殊值EOF.

    【讨论】:

    • 那是因为你不会在fp2 中写入任何内容,k &gt; n 的情况除外。 :) (你可以很容易地加入这两种情况,也可以不先计算行数:在确定之后你永远不会使用n。)
    • 是的,我后来想通了。仍然非常感谢您的帮助! :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多