我正在参加各种编程奥林匹克竞赛,并试图提高时间效率。我正在寻找最快的获取输入的方法,使用gcc编译器而不需要任何外部库。
我以前使用过cin和cout,但发现scanf和printf更快。还有更快的方法吗?我并不太在意空间复杂度,更喜欢更好的时间效率。
我正在参加各种编程奥林匹克竞赛,并试图提高时间效率。我正在寻找最快的获取输入的方法,使用gcc编译器而不需要任何外部库。
我以前使用过cin和cout,但发现scanf和printf更快。还有更快的方法吗?我并不太在意空间复杂度,更喜欢更好的时间效率。
流相比C-API函数总是慢的这个观点是一个普遍的误解,因为默认情况下,它们与C层同步。所以,是的,这是一种特性而不是错误。
如果不牺牲类型安全(和可读性,根据您的口味),您可能会通过使用以下方法在流中获得更好的性能:
std::ios_base::sync_with_stdio (false);
#include <cstdio>
#include <iostream>
template <typename Test>
void test (Test t)
{
const clock_t begin = clock();
t();
const clock_t end = clock();
std::cout << (end-begin)/double(CLOCKS_PER_SEC) << " sec\n";
}
void std_io() {
std::string line;
unsigned dependency_var = 0;
while (!feof (stdin)) {
int c;
line.clear();
while (EOF != (c = fgetc(stdin)) && c!='\n')
line.push_back (c);
dependency_var += line.size();
}
std::cout << dependency_var << '\n';
}
void synced() {
std::ios_base::sync_with_stdio (true);
std::string line;
unsigned dependency_var = 0;
while (getline (std::cin, line)) {
dependency_var += line.size();
}
std::cout << dependency_var << '\n';
}
void unsynced() {
std::ios_base::sync_with_stdio (false);
std::string line;
unsigned dependency_var = 0;
while (getline (std::cin, line)) {
dependency_var += line.size();
}
std::cout << dependency_var << '\n';
}
void usage() { std::cout << "one of (synced|unsynced|stdio), pls\n"; }
int main (int argc, char *argv[]) {
if (argc < 2) { usage(); return 1; }
if (std::string(argv[1]) == "synced") test (synced);
else if (std::string(argv[1]) == "unsynced") test (unsynced);
else if (std::string(argv[1]) == "stdio") test (std_io);
else { usage(); return 1; }
return 0;
}
使用g++ -O3编译,并使用一个大文本文件:
cat testfile | ./a.out stdio
...
0.34 sec
cat testfile | ./a.out synced
...
1.31 sec
cat testfile | ./a.out unsynced
...
0.08 sec
std::cin >> a >> b >> c
与scanf ("%d %d %d", &a, &b, &c);
之类的内容。我保证,在优化的情况下(即不处于调试模式),性能差异将是微妙的。#include <cstdio>
#include <iostream>
template <typename Test>
void test (Test t)
{
const clock_t begin = clock();
t();
const clock_t end = clock();
std::cout << (end-begin)/double(CLOCKS_PER_SEC) << " sec\n";
}
void scanf_() {
char x,y,c;
unsigned dependency_var = 0;
while (!feof (stdin)) {
scanf ("%c%c%c", &x, &y, &c);
dependency_var += x + y + c;
}
std::cout << dependency_var << '\n';
}
void unsynced() {
std::ios_base::sync_with_stdio (false);
char x,y,c;
unsigned dependency_var = 0;
while (std::cin) {
std::cin >> x >> y >> c;
dependency_var += x + y + c;
}
std::cout << dependency_var << '\n';
}
void usage() { std::cout << "one of (scanf|unsynced), pls\n"; }
int main (int argc, char *argv[]) {
if (argc < 2) { usage(); return 1; }
if (std::string(argv[1]) == "scanf") test (scanf_);
else if (std::string(argv[1]) == "unsynced") test (unsynced);
else { usage(); return 1; }
return 0;
}
结果:
scanf: 0.63 sec
unsynced stream: 0.41
一般来说,缓冲输入是最快的。你越不经常刷新输入缓冲区,输入速度就会越快。关于这个话题的全面而且非常有启发性的讨论,请参见此问题。简而言之,使用大缓冲区大小的read()是最快的,因为它几乎直接在你的操作系统中对应相应的系统调用。
可能 scanf 比使用流略快一些。虽然流提供了很多类型安全性,并且不必在运行时解析格式字符串,但它通常具有不需要过多的内存分配的优点(这取决于您的编译器和运行时)。也就是说,除非性能是您唯一的终极目标并且您处于关键路径上,否则您应该真正倾向于更安全(更慢)的方法。
这里 Herb Sutter 写了一篇非常美味的文章
http://www.gotw.ca/publications/mill19.htm
这篇文章详细介绍了字符串格式化程序(如sscanf和lexical_cast)的性能,以及影响它们运行速度快慢的因素。这与C风格IO和C++风格之间的性能影响可能有些类似。格式化程序的主要区别在于类型安全性和内存分配数量。