前言:本文章用于收集比赛中的各种读入数据的操作,使用最快的速度选择最佳的读入输出方式。帮助自己整理和积累一些读入操作,使得能快速的对读入的数据进行反应。
字符串读入问题
不含空格的字符串读入
对于一般的题目 , 可能包含一些问题。
假设:
3 2
asdja1
kjldfa1
fdsfjA
其中只包含小写字母 , 大写字母 , 数字的。我们可以直接使用std::cin >> s 来读入一个字符串 非常好操作 下面是读入的代码
C ++ 读入方式
std::cin >> n >> m;
for (int i = 0; i < n; i ++ ) {
std::cin >> s;
std::cout << s << '\n';
}
C 语言读入方式
int n , m;
char s[100];
scanf("%d%d\n" , &n , &m);
for (int i = 0; i < n; i ++ ) {
scanf("%s" , s);
printf("%s\n" , s);
}
效果
含空格的字符串读入
我们知道scanf , cin 读入都会以 "tab(\t)" , "__ (空格)" , "\n(换行)" 标记为读入结束符(在读入不是以上三种字符的内容之后的结束符)
所以对于含空格或者\t 的字符串就存在读入不完全的情况
给出例子:
3 2
as d ja1
kj l dfa1
fdsfj A
如何解决呢?
方案一:
char s[100];
scanf("%d%d\n" , &n , &m); // 注意这里的 "\n" 表示输入必须要这个格式
for (int i = 0; i < n; i ++ ) {
gets(s);
printf("%s\n", s);
}
这里的scanf 结束之后会按回车然后结束输入 , 但是这个回车会被 gets 吃掉导致多读 所以需要scanf("%d%d\n") , 规定格式 ,让scanf 吃掉即可(scanf 吃掉之后不会影响前面的数据读入)
char s[100];
scanf("%d%d" , &n , &m);
getchar(); // 这样也可以
for (int i = 0; i < n; i ++ ) {
gets(s);
printf("%s\n", s);
getchar() 吃掉 '\n'
对于有的OJ不支持gets 怎么办 ?
引入 getline 函数 , 是gets()的绝对的平替
getline 函数
- istream& getline (istream& is, string& str, char delim)
- istream& getline (istream& is, string& str)
对于这个函数:
- istream& is 是输入流 , 笔者使用它的应该是 cin
- string& str 读入的目的字符串
- char delim 以delim作为输入结束符 , 默认是 '\n'
在此举例以“#”结束
我们知道了如何读入含空格的字符串的函数了? 那么会不会出现吃掉‘\n’的情况呢?
答案:会
int main(){
std::ios::sync_with_stdio(0);
std::cin.tie(0);
std::cout.tie(0);
std::string s;
std::cin >> n >> m;
getchar();
for (int i = 0; i < n; i ++ ){
getline(std::cin , s);
std::cout << s << '\n';
}
return 0;
}
真正的问题其实是同步流被关闭了!
那么我们来看看我们将同步流开启会出现什么?
int main(){
// std::ios::sync_with_stdio(0);
// std::cin.tie(0);
// std::cout.tie(0);
std::string s;
std::cin >> n >> m;
getchar();
for (int i = 0; i < n; i ++ ){
getline(std::cin , s);
std::cout << s << '\n';
}
return 0;
}
这样却是可以的!
考虑到效率问题 , 关闭掉同步流对于大的数据读入可能会TLE。所以说我们需要考虑一种比较通用的方法 那么只能使用scanf 函数读入 , 字符串的使用getline读入 。
std::string s;
int n , m;
scanf("%d%d\n" , &n , &m);
for (int i = 0; i < n; i ++ ){
getline(std::cin , s);
std::cout << s << '\n';
}
本人还是没有发现效率比较好且简洁的输入输出方式 , 希望我以后能学习到!
update:
关于我们关闭同步流 ,getchar() 就无法使用的问题,在一次与别人交流的过程中发现一个更好的方法
-
cin.get() 类似于C语言的getcahr() , 但是在关闭同步流后我们无法正常使用getchar()吸掉'\n',所以可以使用cin.get()。
-
cin.ignore() 清除读入的一个字符,也是可以关掉同步流。
-
为什么关掉同步流不能使用C语言的读入输出呢? 因为cin 和 printf 不会运行在同一个线程上,于是输出乱序了。貌似,我了解的是因为C++ ,为了兼容C语言,会有一个缓冲区,然后关掉同步流会导致这个缓冲区有问题。我不太了解。反正记住一点 , 关掉同步流,就不能兼容C语言读入输出函数了,不然容易出错。
int n;
int main(){
std::ios::sync_with_stdio(0);
std::cin.tie(0);
std::cout.tie(0);
std::cin >> n;
std::string s;
std::cin.get();
// std::cin.ignore() 也可以
getline(std::cin , s);
std::cout << s;
return 0;
}
输入读到文件末尾
这个的话比较的简单 笔者给出两个方式
C语言方式的读入
int n;
while(scanf("%d" , &n) != EOF){
printf("%d\n", n);
}
C++ 方式的读入
std::ios::sync_with_stdio(0);
std::cin.tie(0);
std::cout.tie(0);
int n;
while(std::cin >> n){
std::cout << n << '\n';
}
依靠换行结束输入形式(sstream)
有时候时候,比如做图论题的时候,给定一条链,不会给定读入结点数的
类似于这样 , 给定3条链。但是不会说这条链长度。
对于这种情况,我们选择使用 <sstram> 这个头文件中的 stringstream
std::cin >> n >> m;
std::string line;
getline(cin , line);
while (n -- ){
getline(cin , line);
stringstream ssm(line);
int p = 0;
std::vector<int> t;
while (line >> p) t.push_back(p);
for (auto x : t)
std::cout << x << ' ';
}
}
将一行信息读入line ,再通过stringstream 过滤掉所有空格, 将数据分离出来