1.
输入学生信息,姓名 成绩(成绩的数目不一定)
输出每个学生的学号和平均成绩,以及不及格课程数超过2的学生,按不及格课程数从大到小排好序输出。
自己编的测试用例:
输入:
xiaoming 99 88 5 44 98 52
zhangsan 55 85 74
huahua 6 5 2 8 88
lixiang 14 52 69 74 33
输出:
不及格数超过2的学生:
huahua的不及格数目为:4
xiaoming的不及格数目为:3
lixiang的不及格数目为:3
zhangsan的平均成绩为:71.3333
xiaoming的平均成绩为:64.3333
lixiang的平均成绩为:48.4
huahua的平均成绩为:21.8
使用了简单的class
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
class stu {
public:
string name, info;
vector<int> score; //这个记录成绩的数组其实没用上
int not_pass = 0;
double aver_score;
stu(string info){ //使用输入的一整行信息构造学生对象
this->info = info;
for (int i = 0; i < info.length(); i++) {
if (info[i] >= 'a' && info[i] <= 'z')
i = getName(i); //返回的i指向name后面的空格
else if (info[i] >= '0' && info[i] <= '9')
i = getScore(i);
}
}
private:
int total_score = 0, num = 0;
int getName(int i) {
int start = i;
while (info[i] >= 'a' && info[i] <= 'z')
i++;
name = info.substr(start, i);
return i;
}
int getScore(int i) {
int sco = 0;
while (info[i] >= '0' && info[i] <= '9') {
sco = sco * 10 + (info[i] - '0');
i++;
}
score.push_back(sco);
total_score += sco;
num++;
aver_score = total_score * 1.0 / num;
if (sco < 60)
not_pass++;
return i;
}
};
bool cmp1(stu a, stu b) { return a.not_pass > b.not_pass; }
bool cmp2(stu a, stu b) { return a.aver_score > b.aver_score; }
int main()
{
string info;
vector<stu> s;
while (getline(cin, info)) {
s.push_back(stu(info));
}
sort(s.begin(), s.end(), cmp1);
cout << "不及格数超过2的学生:" << endl;
for (auto it = s.begin(); it != s.end(); it++) {
if (it->not_pass >= 2)
cout << it->name << "的不及格数目为:" << it->not_pass << endl;
else
break;
}
cout << endl;
sort(s.begin(), s.end(), cmp2);
for (auto it = s.begin(); it != s.end(); it++)
cout << it->name << "的平均成绩为:" << it->aver_score << endl;
return 0;
}
2.
输入字符串,输出字符串中包含的数字,比如 2.3ABC0-2.3 输出 2.3 0 -2.3。
注意一些特殊的情况如+004.500值为+4.5。
方法1
(老实本分版)
是通过两个判断数字开始和结束的函数判断数字范围。再在这个范围内生成该数字。输入字符串中仅支持包含字母
,数字
和+
、-
、.
三个字符。
运行截图:
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
string t;
bool start_sign(char c) //遇到的可以认为是一个数开始的字符
{
if (c >= '0' && c <= '9')
return true;
else if (c == '+' || c == '-')
return true;
return false;
}
bool end_sign(char c) //遇到的可以认为是一个数结束的字符
{
if (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z')
return true;
else if (c == ' ' || c == '+' || c == '-')
return true;
return false;
}
int printNum(int i)
{
double num = 0;
double _point = 1;
bool exist_plus = false;
int flag = 1; //符号位
do{ //不使用while的原因是+和-既是开始符也是结束符,所以为避免冲突,第一次执行时不应该判断。
if (t[i] <= '9' && t[i] >= '0') {
if (_point >= 1) { //_point未遇到小数点前恒为1
num = num * 10 + t[i] - '0';
}
else {
num = num + _point * (t[i] - '0');
_point = _point * 0.1;
}
}
else if (t[i] == '-')
flag *= -1;
else if (t[i] == '+')
exist_plus = true;
else if (t[i] == '.')
_point *= 0.1;
} while (!end_sign(t[++i])&&i<t.length());
if (exist_plus)
cout << '+';
cout << num * flag << ' ';
return i-1;
}
int main()
{
while (getline(cin, t)){
for (int i = 0; i < t.length(); i++) {
if (start_sign(t[i])) {
i = printNum(i); //返回的i是最后一个数字内的符号
}
}
cout << endl << endl;
}
}
(2020.4.17)
方法2 巧用字符流
感觉方法1还是有点麻烦,可以巧用我前面哪篇博客提到的字符串流,发挥C++的优势嘛
诸如去后缀0、处理小数点等等杂事都不用管,交给流就完了,不过要对流操作有一个熟练的掌握
需要注意的是流输入如果错误,会自动在流中添加一个错误标记,使流无法再次被读入(防止一连串的错误),这就要求在else中必须clear()掉错误标记后才能继续读入。
如果没想起来清除错误标记,为了处理这个错误,也可以重新创建一个流istringstream ii(s);
然后再从新流读 ii >> ret;
。
#include<iostream>
#include<string>
#include<sstream>
using namespace std;
string getNum(string s)
{
string ret;
istringstream i(s); //从s中创建输入流
double t;
if(i >> t){ //从流中读一个double
if(s[0]=='+')
cout << '+'; //有加号则先输出一个加号
cout << t << " ";
i >> ret; //把剩下的字符串返回
return ret;
}
else{ //流前面并不是数字,无法读入
i.clear(); //由于上一次流读入错误,流中存在错误标记,无法再次读入,需要先清除错误标记
i >> ret;
return ret.substr(1); //去掉一个字符,返回
}
}
int main()
{
string s;
getline(cin,s);
while(s != ""){ //循环到删光为止
s = getNum(s);
}
}