C++ 如何改进这个字符计数算法
我想构造一个函数,执行一个文件分析,在数组中返回从0x0到0xff的每个字节计数及其频率 所以,我写了这个原型:C++ 如何改进这个字符计数算法,c++,c,algorithm,C++,C,Algorithm,我想构造一个函数,执行一个文件分析,在数组中返回从0x0到0xff的每个字节计数及其频率 所以,我写了这个原型: // function prototype and other stuff unsigned int counts[256] = {0}; // byte lookup table FILE * pFile; // file handle long fsize; // to store file size unsign
// function prototype and other stuff
unsigned int counts[256] = {0}; // byte lookup table
FILE * pFile; // file handle
long fsize; // to store file size
unsigned char* buff; // buffer
unsigned char* pbuf; // later, mark buffer start
unsigned char* ebuf; // later, mark buffer end
if ( ( pFile = fopen ( FNAME , "rb" ) ) == NULL )
{
printf("Error");
return -1;
}
else
{
//get file size
fseek (pFile , 0 , SEEK_END);
fsize = ftell (pFile);
rewind (pFile);
// allocate space ( file size + 1 )
// I want file contents as string for populating it
// with pointers
buff = (unsigned char*)malloc( sizeof(char) * fsize + 1 );
// read whole file into memory
fread(buff,1,fsize,pFile);
// close file
fclose(pFile);
// mark end of buffer as string
buff[fsize] = '\0';
// set the pointers to beginning and end
pbuf = &buff[0];
ebuf = &buff[fsize];
// Here the Bottleneck
// iterate entire file byte by byte
// counting bytes
while ( pbuf != ebuf)
{
printf("%c\n",*pbuf);
// update byte count
counts[(*pbuf)]++;
++pbuf;
}
// free allocated memory
free(buff);
buff = NULL;
}
// printing stuff
但这条路比较慢。我正在寻找相关的算法,因为我已经看到了HxD的例子
快点
我认为一次读取一些字节可能是一个解决方案,但我不知道如何解决
我需要帮助或建议
谢谢。假设您的文件不太大,导致系统开始分页,因为您正在将整个内容读取到内存中,那么您的算法与通用数据的算法一样好-
O(n)
您需要删除printf
(如上所述);但除此之外,如果性能不高于提高性能的唯一方法是查看生成的汇编程序-可能编译器没有优化所有反引用(gcc应该这样做)
如果您碰巧对数据集有所了解,那么可能会有一些改进—如果它是位图类型的图像,可能有相同的字节块,那么可能值得进行一点运行长度编码。也可能有一些数据集实际上值得首先对数据进行排序(尽管这将一般情况简化为O(nlog(n))
,因此不太可能
rle看起来有点像(未经测试,可能是我头脑中的次优免责声明)
你可以经常把程序大小增加来提高速度,我认为在你的情况下可以很好地工作。我会考虑用未签名的短指针替换你的无符号char指针,并且一次有效地处理两个字节。这样,数组索引增量的一半,CALUCL的一半。向累加器中输入偏移量的一半,累加次数的一半,以及查看循环是否完成的测试次数的一半
正如我所说,这将以增加程序大小为代价,因此您的累加器数组现在需要65536个元素,而不是256个元素,但这是一个很小的代价。我承认在易读性方面也有一个折衷 最后,您必须对我新的更大累加器的所有65536个元素运行一个索引,并用0xff屏蔽它以获得第一个字节,并将其移位8位以获得第二个字节。然后,您将拥有与原始累加器相对应的两个索引,您可以从那里将2个累加到原始256累加器中 请注意,尽管您一次可以处理几乎所有的文件2个字节,但如果您的文件大小是奇数字节,则必须自行处理最后一个字节p.p.S.请注意,如果您想让备用的3个CPU内核做一些比摆弄它们的拇指更有用的事情,那么这个问题很容易在4个线程之间并行处理;-)如果您不打印每个字符,速度会快得多。I/O非常慢。您需要触摸文件中的每个字节,使其更快的是以块的形式读取它(正如您所做的),因此它是一个很好的实现(对于
C
)。有一件事让我很恼火,那就是你一次缓冲了整个文件,这对大文件来说是个坏主意。。您应该逐块读取它(每个块的大小应为2:10242048,…)。并从循环中删除printf
。您可能应该printf
每个字符。;-)没有理由认为缓冲区必须是文件的大小。让它有一些适合寻呼机的尺寸,比如8KiB。此外,如果不将每个字符打印到标准输出,处理速度会快得多。试着分析一下时间的走向。这个问题更适合你
unsigned int cur_count=1;
unsigned char cbuf=*(++pbuf);
while ( pbuf != ebuf)
{
while( pbuf != ebuf && cbuf == *pbuf )
{
cur_count++;
pbuf++;
}
counts[cbuf]+=cur_count;
cur_count=0;
}
counts[cbuf]+=cur_count;