一、背景
平常做Leecode可能写习惯了,可能有的小伙伴还不习惯做牛客上的空文本的输入输出,有的时候算法搞出来了,却卡在了数据的输入输出上,导致代码不能AC。下面我总结了一些常用的数据输入输出格式,仅供参考! 注:基于C/C++编程语言
二、数据输入
下面是一个华为笔试编程题为例:
Q:老师想知道从某某同学当中,分数最高的是多少,现在请你编程模拟老师的询问。当然,老师有时候需要更新某位同学的成绩.
输入包括多组测试数据。 每组输入第一行是两个正整数N和M(0 < N <= 30000,0 < M < 5000),分别代表学生的数目和操作的数目。 学生ID编号从1编到N。 第二行包含N个整数,代表这N个学生的初始成绩,其中第i个数代表ID为i的学生的成绩 接下来又M行,每一行有一个字符C(只取‘Q’或‘U’),和两个正整数A,B,当C为'Q'的时候, 表示这是一条询问操作,他询问ID从A到B(包括A,B)的学生当中,成绩最高的是多少 当C为‘U’的时候,表示这是一条更新操作,要求把ID为A的学生的成绩更改为B。
输入例子:
5 7
1 2 3 4 5
Q 1 5
U 3 6
Q 3 4
Q 4 5
U 4 5
U 2 9
Q 1 5
咱先不研究这道题该怎么做,咱就说说这道题该怎么输入呢,上面给的例子只是一次的测试用例,我们的程序要保证可以通过很多很多这种格式的测试用例,首先是不是想到用while循环呢。
在说之前,首先了解一下比较常用的数据流读取函数:
1、scanf()函数
头文件:#include<stdio.h>**
**作用:**用户指定的格式从键盘上把数据输入到指定的变量之中。scanf函数返回成功读入的数据项数,读入数据时遇到了“文件结束”则返回EOF。
常用的形式一般都是数字、字符以及字符串的输入:
scanf("%d%c%s",&x,&y,z); //把数字输入到x,字符输入到y,字符串输入到z中
如果输入的时候数据之间有空格或者逗号怎么办
scanf("%d%d",&a,&b); //一个数据给a,空格给b
scanf("%d %d",&a,&b); //一个数据给a,第二个数据给b
//两个数据之间有逗号的情况
scanf("%d,%d",&a,&b); //一个数据给a,第二个数据给b
字符串数据怎么办:用sscanf()函数
sscanf函数原型为int sscanf(const char *str, const char *format, ...)。将参数str的字符串根据参数format字符串来转换并格式化数据,转换后的结果存于对应的参数内。具体功能如下:
-
根据格式从字符串中提取数据。如从字符串中取出整数、浮点数和字符串等。
-
取指定长度的字符串
-
取到指定字符为止的字符串
-
取仅包含指定字符集的字符串
-
取到指定字符集为止的字符串
例如:
int main(){
char s[15] = "123.432,432 11";
int n;
double f1;
int f2;
sscanf(s, "%lf,%d%n", &f1, &f2, &n);
cout<<f1<<" "<<f2<<" "<<n;
return 0;
}
//输出结果
123.432 432 11
2、cin的使用
使用格式:
#include<iostream>
using namespace std;
首先要了解cin是输入输出流的一个对象,具体来说是istream的对象。主要形式: cin >> x,x可以是数字、字符或者字符串,如果是输入的是一个字符串,**cin使用空白、空格、制表符和换行符来确定字符串的结束位置。**例如:
输入字符串:Bronming is nice! 如果用cin输入,就只能得到Bronming,因为后面有空格,就代表一次输入结束了。
注意:cin和scanf()都是输入数据流,可以同时输入最后也可以同时输出。也就是说我可以先把数据输入到流中,然后程序会依次处理这些数据,而不用每处理一次都cin一下。
那么如何输入一个字符串呢?用getline()
3、getline()
**该函数读取一行数据,通过回车来确定输入的结尾!**常用的形式:
getline(cin,str);
看一种特殊的情况:混合输入字符串和数字怎么办
int number;
string name;
cin >> number;
getline(cin,name);
//此时出现的问题是,第一次cin输入结束后会留下一个回车符,然后getline看到回到符以后以为是遇到空行,然后就输入结束,导致名字无法输入。
//解决的办法:
int number;
string name;
cin >> number;
cin.get(); //先读取空行
getline(cin,name);
4、输入的另一种常用形式Stringsteam ss
头文件 #include<sstream>
sstream 主要用来进行数据类型转换,由于 <sstream> 使用 string 对象来代替字符数组(snprintf方式),就避免缓冲区溢出的危险;而且,因为传入参数和目标对象的类型会被自动推导出来,所以不存在错误的格式化符的问题。简单说,相比c库的数据类型转换而言,<sstream> 更加安全、自动和直接。
注意:流操作,和cin cout类似,只是一个是屏幕流一个是字符流。如果遇到空格就结束了,遇到字符就读一个字符,他是从cin继承来的,符合cin的特性。
在笔试中会经常碰到先读入一行字符串,然后提取里面的数字等操作。这时我们会首先想到sscanf()函数,还有一种方式就是用stringsteam ss。具体怎么操作呢?
int main(){
string s = "1 23 # 4";
stringstream ss;
ss<<s;
while(ss>>s){
cout<<s<<endl;
int val = convert<int>(s);
cout<<val<<endl;
}
return 0;
}
//输出结果:1 1 23 23 # 0 4 4
再比如:
#include<iostream>
#include<string>
#include<sstream>//stringstream的头文件
using namespace std;
int main()
{
string line;
while(getline(cin,line))
{
int sum=0,x;
stringstream ss(line);//复制line到stringstream ss
while(ss>>x)//相当于输入一个个单词,会自动将一个个单词转化为数字
{
sum+=x;
}
cout<<sum<<endl;
}
return 0;
}
说明一下:定义完一个ss之后,把字符串传输到流有两种方式:
streamstring ss(str); //初始化传入
streamstring ss;
ss<<str; //操作符传入,你看箭头的方向,向着ss就是给ss传值
然后一行字符串就呆在ss里面了,这时候还是字符的形式,如果你想把字符转成数字的形式,就直接使用ss>>x就行了,注意x是数字格式的变量,也就是说ss把字符吐给了变量x,但是变量x就是我们想要的数字格式,好处就是完成了类型的自动转化。然后你就可以把数字转入到数组里面进行处理了。提醒一下:如果字符串中含有,等特殊字符,则需要转换成空格在进行上诉操作,或者使用sscanf()函数。
如果说是数字变成字符串:
int num = 126;
streamstring ss;
ss<<num;
string str = ss.str();
cout << str << endl;
例如从文件读取数据,一行数据的格式为1,2,2,5,6:
void Read_Testdata() {
int i=0;
ifstream inFile;
inFile.open(Testdata_name);
if(!inFile.is_open()) {
cout << "打开测试文件失败!!!" << endl;
exit(0);
}
while(inFile) {
string line;
unsigned int id;
getline(inFile,line); //读取一行数据
//,转成空格
for(unsigned int i = 0; i < line.length(); i++){
if(line[i] == ',')
line[i] = ' ';
}
stringstream ss(line); //定义一个stringstream类型的对象ss并用line进行初始化
for(int j=0;j<3;j++)
{
ss >> id; //先把数据进行转换到unsigned_int类型,然后从流中读取数据到id中。
num[i][j] = id;
}
i++;
}
}
5、实际操作
既然你知道这么多输入函数,我想应该足够了。你现在再看看上面那个题,学会输入了吗?
#include<iostream>
using namespace std;
int main() {
int N,M;
while(cin>>N>>M) { //这不就把第一行的输入处理了吗
//看第二行数据是一个数组吗,而且题目说明输入的数字,所以可以一次把数据循环输入到一个数组里面去
int ID[N];
for(int i=0;i<N;i++)
cin >> ID[i];
//题目要求接下来又是M行,每一行包含一个字符和两个正整数,根据题目可知,我需要知道这个字符是多少,
//需要知道这两个正整数是多少,所以我定义一个字符和两个数字变量。
char ch;
unsigned int a,b;
for(int i=0;i<M;i++) {
//下面就是处理一行数据,注意这一行数据不是一个字符串,所以可以用
cin >> ch >> a >> b;
或者
scanf("%c%d%d",&ch,&a,&b);
//剩下的就是对这一行进行具体的操作了
{}
}
}
三、数据输出
数据输出就不用多说了,常用的就是printf("%d",a) 和cout << stri << endl;
还有就是一个sprintf函数,原型为 int sprintf(char *str, const char *format, ...)。作用是格式化字符串,具体功能如下所示:
-
将数字变量转换为字符串。
-
得到整型变量的16进制和8进制字符串。
-
连接多个字符串。
int main(){ char str[256] = { 0 }; int data = 1024; //将data转换为字符串 sprintf(str,"%d",data); //获取data的十六进制 sprintf(str,"0x%X",data); //获取data的八进制 sprintf(str,"0%o",data); const char *s1 = "Hello"; const char *s2 = "World"; //连接字符串s1和s2 sprintf(str,"%s %s",s1,s2); cout<<str<<endl; return 0; } 一般常见的格式串: %% 印出百分比符号,不转换。 %c 整数转成对应的 ASCII 字元。 %d 整数转成十进位。 %f 倍精确度数字转成浮点数。 %o 整数转成八进位。 %s 整数转成字符串。 %x 整数转成小写十六进位。 %X 整数转成大写十六进位。 %n sscanf(str, "%d%n", &dig, &n),%n表示一共转换了多少位的字符四、实际练习
光说不练假把式,咱还是以上面的华为真题为例: 这个程序并不难,就会老师问一次我回答一次,就是寻找数组的最大值,并且实时更新成绩。
#include<iostream> using namespace std; int main(){ int N,M; while(cin>>N>>M) { int nums[N+1]; for(int i=1;i<=N;i++) cin >> nums[i]; char ch; unsigned int a,b; for(int i=0;i<M;i++) { cin >> ch >> a >> b; //更新数据 if(ch=='U') { nums[a] = b; } //寻找最大值 else if(ch=='Q') { if(a>b) swap(a,b); int res=nums[a]; for(int i=a;i<=b;i++) { res = max(res,nums[i]); } cout << res << endl; //输出部分 } } } return 0; }我没有加详细注释,其实思路很简单,关键体现程序的输入输出! OK,代码通过
五、总结
以上就是最简单的输入输出,以后还会遇到其他的形式,我还会实时更新的,记得交流哦!