目录
写在前面:这道题需要注意的就是最后一个数值转换,记得转成double呀!
一、题目
ppp考试说明
- 考试时间:合计2小时。选择题部分30分钟交卷,允许提前交卷。
- 考试过程中,不能连接未经指定网站或服务器。
- 闭卷考试部分,不能查阅任何类型的参考资料。
- 开卷考试部分,可以查阅纸质文档,不能查阅任何类型的电子文档。
- 考试过程中,不得使用任何形式的电子存储设备,不可使用手机。
- 违反上述2-5条者,视为考试作弊。
选择题答题方式(20分,闭卷,严禁使用vs编程环境进行尝试)
- 打开浏览器,在地址栏中输入http://192.168.151.175:81,点击相应链接进入登录页面。
- 按要求输入两遍自己的学号。
- 点击“登录”按钮即可进入答题页面。如考试尚未开始,系统会进入等待页面并倒计时。考试开始时间到,系统会自动进入答题页面。
- 在页面左侧选择题号,页面右侧即会显示相应的题目。考生只需点击选择相应的选项。
- 答题过程中如关闭浏览器或出现系统故障导致计算机重新启动,系统不会丢失之前已经完成的题目的答案。考生可以打开浏览器重新登录并继续考试。
- 答题完成后,点击“交卷”按钮即可完成交卷。交卷后不能再次登录系统继续考试。
- 考试结束时间到,系统会自动收卷。
编程题提交方式(80分,开卷)
- 提交前务必关闭vs2005、vs2008或vs2010编程环境。
- 所有源程序内容必须仅包含在一个源程序文件(CPP文件)中。
- 在浏览器的地址栏中输入http://192.168.151.175:81,点击相应链接进入提交页面。
- 按要求输入两遍自己的学号。
- 点击“选择文件”按钮,选择自己的源程序文件。点击“提交”按钮提交。
- 如提交成功,系统会显示相关信息。如果提交不成功,请重复步骤16-18。
- 提交成功后,可点击“查看内容”按钮检查提交的内容。
按以下要求编写程序
题目说明
请各位考生从课程信息发布网站下载数据文件data.txt,然后将该数据文件手动保存在D盘根目录下。该文件中的数据以文本形式存储,每行包含3列数据,格式如下:A列和B列都是单词,C列是同一行A列和B列中单词共同出现的次数,列之间用tab隔开。文件总行数在千行以上,A列或B列的单词可能重复,如下面例子所示:
A B C
打 电话 2
喝 啤酒 3
打 人 5
吃 苹果 6
打 电话 1
… … …
上面第一行表示“打”和“电话”两个单词在文档1中共同出现了2次,最后一行表示这两个单词在文档2中一起出现了1次,诸如此类。
定义结构体unit和unita,用来存储如下数据:
typedef struct {
string a; //存储A列的单词
string b; //存储B列的单词
int cab; //存储单词a和单词b在所有文档中共同出现次数的总和
} unit;
typedef struct{
string a; //A列的单词
int ca; //单词a在所有文档中出现的次数总和
}unita;
比如在上面的示例中,“打”和“电话”共同出现的次数总和为2+1=3次,“打”单独出现的次数总和为2+5+1=8次。
请按要求依次完成如下操作:
- 编写一个函数read_data,读取data.txt文件中的所有数据,并将它们存放在一个unit的向量vunit中,要求向量里所有单元的a和b都不重复,对重复的a和b,将它们共同出现次数累加到c中。(注意:向量不同单元中的单个a或单个b可以相同,但不允许a和b同时相同)
- 编写一个函数cal_counts,以引用方式将vunit传递给该函数,并计算A列单词在所有文档中出现的次数,将计算结果保存在另一个向量vector<unita> vunita中。
- 编写一个排序函数sort_units,将向量vunit中的元素按照出现次数cab由高到低排序。
- 编写一个重载的排序函数sort_units,将向量vunita中的元素按照出现次数ca由高到低排序。
- 编写一个函数print_top_units,将排序后的向量vunita中的前20个元素按下面显示格式输出到屏幕上:
显式a,显示宽度为10,不足的以“S”补齐,向右对齐 | 显式ca,显式宽度5,不足的以“$”补齐,向右对齐 |
打 | $$$$8 |
吃 | $$$$6 |
- 编写一个条件概率计算函数cal_probs,以引用方式将vunit和vunita传递给该函数,计算一个概率表,并将该概率表输出到文件prob.txt中(同样存放在d盘根目录下),文件每一行格式为:A列单词a ||| B列单词b||| p(b|a),即给定A列一个单词的情况下,B列某个单词出现的概率p(b|a)= cab/ca,如按照上面的例子p(电话|打)=3/8=0.375。按照vunit中元素的顺序将以上概率输出到文件prob.txt中。(注意,只需计算vunit中出现的A列单词和B列单词对的概率,vunit中没有出现的A、B列单词组合无需考虑)
- main函数如下:
int main() {
string rfn = "d:\\data.txt";
string wfn ="d:\\prob.txt";
vector<unit> vunit;
vector<unita> vunita;
read_data(rfn, vunit);
cal_counts(vunit, vunita);
sort_units(vunit);
sort_units(vunita);
cout << "A列单词出现次数前20:" << endl;
print_top_units(vunita);
cout <<"计算条件概率并输出到:" <<wfn<< endl;
cal_probs(vunit, vunita, wfn);
return 0;
}
注意: 不允许修改main函数,每修改一处,扣3分;
评分标准
(编程题满分为80分)
大项 | 子项 | 评分项 | 应得分 | 实得分 |
正 确 性 70分 | 结果(70分) 含编译子项5分 | 文件读取函数read_data | 15 | |
次数统计函数cal_counts | 15 | |||
两个向量排序函数sort_units | 共10分,每个5分 | |||
向量打印函数print_top_units | 10 | |||
概率计算和输出函数cal_probs | 15 | |||
上述各项都不得分 | 见编译子项 | 本项不得分 | ||
程序运行出现异常 | -10 | |||
程序死循环 | -10 | |||
修改main函数 | -3(每处修改) | |||
编译(5分) | 编译连接均通过(无warning) | 5 | ||
编译连接均通过(有warning) | 4 | |||
编译通过、连接不通过 | 3 | |||
编译、连接均不通过 | 0 | |||
可 读 性 10分 | 缩进对齐(4分) | 正确运用缩进对齐规则 | 4 | |
有缩进对齐但不完全符合要求 | 2 | |||
没有使用缩进对齐规则 | 0 | |||
注释(3分) | 有详细且正确的注释 | 3 | ||
有注释,但不够详细 | 2 | |||
完全没有注释 | 0 | |||
变量命名(3分) | 变量命名有规则 | 3 | ||
变量命名有规则、但规则使用不一致 | 2 | |||
变量命名无规则 | 0 | |||
总分(满分80分) |
二、代码
#include <iostream>
#include<vector>
#include<string>
#include<fstream>
#include<algorithm>
#include<iomanip>
using namespace std;
typedef struct {
string a; //存储A列的单词
string b; //存储B列的单词
int cab; //存储单词a和单词b在所有文档中共同出现次数的总和
} unit;
typedef struct{
string a; //A列的单词
int ca; //单词a在所有文档中出现的次数总和
}unita;
void read_data(string path,vector<unit>&t){
ifstream ifile(path);
while(!ifile.eof()){
unit u;
if(ifile>>u.a>>u.b>>u.cab){
int i;
for(i=0;i<t.size();i++){
if(t[i].a==u.a && t[i].b==u.b){
t[i].cab+=u.cab;
break;
}
}
if(i==t.size()){
t.push_back(u);
}
}
}
ifile.close();
}
void cal_counts(const vector<unit>&t,vector<unita>&ta){
for(int i=0;i<t.size();i++){
int j;
for(j=0;j<ta.size();j++){
if(ta[j].a==t[i].a){
ta[j].ca+=t[i].cab;
break;
}
}
if(j==ta.size()){
unita u;
u.a=t[i].a;
u.ca=t[i].cab;
ta.push_back(u);
}
}
}
int cmp1(unit a,unit b){
return a.cab>b.cab;
}
void sort_units(vector<unit>&t){
//将向量vunit中的元素按照出现次数cab由高到低排序
sort(t.begin(),t.end(),cmp1);
}
int cmp2(unita a,unita b){
//将向量vunita中的元素按照出现次数ca由高到低排序。
return a.ca>b.ca;
}
void sort_units(vector<unita>&ta){
//将向量vunit中的元素按照出现次数cab由高到低排序
sort(ta.begin(),ta.end(),cmp2);
}
void print_top_units(const vector<unita>&ta){
/*
5、编写一个函数print_top_units,
将排序后的向量vunita中的前20个元素按下面显示格式输出到屏幕上:
显式a,显示宽度为10,不足的以“S”补齐,向右对齐
显式ca,显式宽度5,不足的以“$”补齐,向右对齐
打 $$$$8
吃 $$$$6
*/
for(int i=0;i<20;i++){
cout<<right<<setfill('S')<<setw(10)<<ta[i].a;
cout<<right<<setfill('$')<<setw(5)<<ta[i].ca<<endl;
}
}
void cal_probs(const vector<unit>&t, const vector<unita>&ta, string path){
/*
A列单词a ||| B列单词b||| p(b|a),
即给定A列一个单词的情况下,B列某个单词出现的概率p(b|a)= cab/ca,
如按照上面的例子p(电话|打)=3/8=0.375。
按照vunit中元素的顺序将以上概率输出到文件prob.txt中。
(注意,只需计算vunit中出现的A列单词和B列单词对的概率,
vunit中没有出现的A、B列单词组合无需考虑)
*/
ofstream ofile(path);
for(int i=0;i<t.size();i++){
double pba;
for(int j=0;j<ta.size();j++){
if(ta[j].a==t[i].a){
pba=(double)t[i].cab/(double)ta[j].ca;
break;
}
}
ofile<<t[i].a<<"|||"<<t[i].b<<"|||"<<pba<<endl;
}
ofile.close();
}
int main() {
string rfn = "d:\\data.txt";
string wfn ="d:\\prob.txt";
vector<unit> vunit;
vector<unita> vunita;
read_data(rfn, vunit);
cal_counts(vunit, vunita);
sort_units(vunit);
sort_units(vunita);
cout << "A列单词出现次数前20:" << endl;
print_top_units(vunita);
cout <<"计算条件概率并输出到:" <<wfn<< endl;
cal_probs(vunit, vunita, wfn);
return 0;
}