我有一个问题需要从控制台输入像下面这样的1000000行输入。
0 1 23 4 5
1 3 5 2 56
12 2 3 33 5
...
...
我曾经使用过scanf,但是它非常慢。有没有一种更快的方式从控制台获取输入?我可以使用read(),但是我不确定每行有多少字节,所以我不能要求read()读取'n'字节。 谢谢, 非常感谢
我有一个问题需要从控制台输入像下面这样的1000000行输入。
0 1 23 4 5
1 3 5 2 56
12 2 3 33 5
...
...
我曾经使用过scanf,但是它非常慢。有没有一种更快的方式从控制台获取输入?我可以使用read(),但是我不确定每行有多少字节,所以我不能要求read()读取'n'字节。 谢谢, 非常感谢
fgets()
组合来读取行,然后使用循环调用strtol()
将字符串转换为整数。这样应该比scanf()
更快,同时仍然比自己进行字符串到整数转换更清晰和更高级。类似这样:typedef struct {
int number[5];
} LineOfNumbers;
int getNumbers(FILE *in, LineOfNumbers *line)
{
char buf[128]; /* Should be large enough. */
if(fgets(buf, sizeof buf, in) != NULL)
{
int i;
char *ptr, *eptr;
ptr = buf;
for(i = 0; i < sizeof line->number / sizeof *line->number; i++)
{
line->number[i] = (int) strtol(ptr, &eptr, 10);
if(eptr == ptr)
return 0;
ptr = eptr;
}
return 1;
}
return 0;
}
read
,直到读取到文件结尾。出于好奇,什么会在控制台中生成如此快速且数量众多的行?
逐行读取(如果缓冲区不足以容纳一行,则扩展并继续使用更大的缓冲区)。
然后使用专用函数(例如atoi)而不是通用函数进行转换。
但最重要的是,建立一个可重复的测试框架,并进行分析以确保改进真正加速了事情。
通过使用fread()
或fread_unlocked()
(如果您的程序是单线程的)来获取输入,可以大大减少执行时间。锁定/解锁输入流只需要一次,所需时间微不足道,因此请忽略它。
以下是代码:
#include <iostream>
int maxio=1000000;
char buf[maxio], *s = buf + maxio;
inline char getc1(void)
{
if(s >= buf + maxio) { fread_unlocked(buf,sizeof(char),maxio,stdin); s = buf; }
return *(s++);
}
inline int input()
{
char t = getc1();
int n=1,res=0;
while(t!='-' && !isdigit(t)) t=getc1(); if(t=='-')
{
n=-1; t=getc1();
}
while(isdigit(t))
{
res = 10*res + (t&15);
t=getc1();
}
return res*n;
}
这个用 C++
实现。在 C
中,你不需要包含 iostream
,函数 isdigit()
隐式可用。
你可以通过调用 getc1()
来获取字符流,并通过调用 input()
获取整数输入。
使用 fread()
的整个想法是要一次性获取所有输入。重复调用 scanf()/printf()
会占用大量时间来锁定和解锁流,在单线程程序中完全是多余的。
还要确保 maxio
的值足以在几个“往返”中获取所有输入(理想情况下只有一个往返)。必要时进行调整。
希望能对你有所帮助!
fread 如果试图读取的字节超过文件中实际存在的字节数,仍将返回。
我发现读取文件最快的方法之一是这样的:
/* 定位到文件末尾 */ fseek(file,0,SEEK_END);
/* 获取文件大小 */ size = ftell(file);
/* 定位到文件开头 */ fseek(file,0,SEEK_SET);
/* 为文件创建缓冲区 */ buffer = malloc(1048576);
/* 每次读入1MB,直到达到size字节等 */
在现代计算机上,利用内存并将整个文件加载到内存中,然后可以轻松地遍历内存。
至少你应该使用fread,并且块大小尽可能大,至少与缓存块或HDD扇区大小一样(最小为4096字节,我个人会使用1048576作为最小值)。你会发现,使用更大的读取请求,fread能够顺序地在一次操作中获取一个大流。这里有些人建议使用128字节是荒谬的...因为你最终会发现驱动器不断寻找,因为调用之间的微小延迟将导致磁头已经超过了下一个几乎肯定包含你想要的顺序数据的扇区。
size
,但这会消耗很多内存,我理解为什么要避免这种情况。 - Chris Lutz