题目 B4:基于关键词的文本排序检索系统
一、 课题内容和要求
题目 B4:
(一)课题内容 “背单词—个性化背词”是背诵英语单词的软件。用户可以根据自己的需求 导入需背诵的词库,并可以编辑自己的词库。背单词时有两种模式供选择:系统 可以给出中文提示,用户输入对应的单词,也可输出单词让用户输入中文意思。 系统判定词义是否正确,如果正确提升该单词熟悉程度,如果不正确给出提示并 降低该单词的熟悉程度,同时对单词按照熟悉程度进行类别划分。
(二)课题要求
- 基本要求 代码要能提供以下几个基本功能。
(1)用户登录: ·新用户可以注册,旧用户直接登录。 ·可以只打卡不背词,直接退出界面。
(2)单词本: ·存储单词基本信息,英文、词性、中文解释等。 ·为了方便用户,可以提供已存储的单词本供用户选择。 ·选择词库维护编辑单词本信息,实现增加、修改、删除、补充(单词已有, 补充新的释义)的功能。
(3)单词背诵及成绩统计: ·按照用户选择的任务词量,随机选择单词预览进行单词学习。 ·单词背诵时有两种模式选择,选择题背诵及拼写单词背诵,支持多次背诵。 ·根据背诵情况对单词进行单词熟悉度归类。 ·可查阅单词本中各类熟悉度的单词总量。
(4)单词复习: ·背诵完全正确时界面显示没有错题继续努力。 ·有错题时可以选择错题重背加强记忆。
(5)退出系统时可以进行打卡,统计背诵单词天数。
\2. 扩展要求
(1)对用户的输入进行一定的正确性检查。
(2)能统计每一个单词出现频率及背诵正确率,供以后出题时提供依据。
【其他要求】
(1)变量、函数命名符合规范。
(2)注释详细:每个变量都要求有注释说明用途;函数有注释说明功能, 对参数、返回值也要以注释的形式说明用途;关键的语句段要求有注释解释。
(3)程序的层次清晰,可读性强。 (4)界面美观,交互方便。
二、需求分析
用户类的使用(class user)实现账号密码的注册和登录,利用析构函数和数组实现对单词本词性、释义的录入、修改和删除,以及单词熟悉度的统计和查询。并利用多个用户自定义函数使功能得到实现 ,示例如下:
图2.1部分用户自定义函数
三、概要设计
图3.1单词背记系统的流程图
注:该程序完成用户的注册必须输出3.退出才能完成用户账号和密码的保存。
首先进行用户账号密码的注册和登录,完成登陆页面后,7个序号分别对应了7项功能,用户可以根据需求输入相应的序号从而实现功能。
对于功能1、2、3:单词本的录入、修改和删除需要根据单词背诵系统的提示正确输出相应数据才能进行。
对于剩下的功能便如图所示进行操作即可:
图3.2功能4、5、6的操作指示图
四、详细设计 (部分核心代码)
头文件的使用
图4.1该函数所使用的头文件
#include 指令会指示 C 预处理器浏览指定的文件作为输入。预处理的输出包含了已经生成的输出,被引用文件生成的输出以及#include指令之后的文本输出。
图4.2调用用户自定义函数
利用析构函数和数组实现对单词本词性、释义的录入、修改和删除以及单词熟悉度的统计和查询。析构函数对象消亡时被自动调用,可以定义析构函数做对象消亡时的善后工作,比如释放内存等
用户类的创建,用于实现用户账号密码的注册和登录**…**
图4.3析构函数和构造函数的使用
类是用户自定义的类型,如果程序中要用到类,必须提前说明,或者使用已存在的类
(别人写好的类、标准库中的类等)
定义用户自定义函数
(单词本检索系统对应的七项功能)
单词本录入、单词本修改、单词本删除、背诵、熟练度统计、熟练度查询、返回登陆
详细代码 如下:
以下1—6的功能接涉及到****cout<< cin>>
使用 cout<< 可以输出各种数据类型的数据,可以多种方式在屏幕上显示输出信息(包括特殊符号)。
使用 cin 从标准输入读取数据时,通常用到的方法有cin>>
、cin.get()
,cin.getline()
。
图4.4 cin和 cout****的相关概念
该用户自定义函数是
用于单词本录入单词、中文含义和单词词性,对应功能****1 单词本录入
图4.5 AddWord函数的定义
该用户自定义函数是
用于单词本中单词、中文含义和单词词性的修改,对应功能2单词本修改
上图接下图
图4.6 Modify Word函数的定义
该用户自定义函数是
用于删除单词本中的单词对应功能****3 单词本删除
图4.7 DeleteWord函数的定义
生成一个不等于特定数的题目随机数
图4.8 RandExceptNum函数的定义
单词背记系统中最重要的函数:
背诵函数
对应功能****4 背诵
注:介于代码过长(约三页左右)便将大部分分析作为注释放在代码中
void ReciteWord() {int dis[100], flag[100];int num, failnum = 0;cout << "请输入此次背词的数量,不超过100:";cin >> num;if (num > 0 && num <= 100) { cout << "此次记忆的单词有如下" << num << "个:"; for (int i = 0; i < num; i++) { dis[i] = rand() % wlen; cout << i + 1 << "\t\t" << word[dis[i]].getvalue() << "\t\t" << word[dis[i]].getnature() << "\t\t" << word[dis[i]].getmean() << endl; } while (1) { failnum = 0; memset(flag, 0, sizeof(flag)); //标志数组置0表示该题目未正确 cout << "输入1开始选择题目背诵,输入2开始拼写背诵,输入3放弃此次背诵:"; int tag; cin >> tag; if (tag == 1) { for (int i = 0; i < num; i++) { int answer = rand() % 2; //answer == 1时答案为B 等于0时正确项为A if (rand() % 2) { cout << "第" << i + 1 << "题:" << "请选择该中文含义对应的英文:" << word[dis[i]].getmean() << ":\tA "; if (answer) { cout << word[RandExceptNum(dis[i])].getvalue() << "\tB " << word[dis[i]].getvalue() << endl; } else { cout << word[dis[i]].getvalue() << "\tB " << word[RandExceptNum(dis[i])].getvalue() << endl; } } else { cout << "第" << i + 1 << "题:" << "请选择该英文单词对应的中文:" << word[dis[i]].getvalue() << ":\tA "; if (answer) { cout << word[RandExceptNum(dis[i])].getmean() << "\tB " << word[dis[i]].getmean() << endl; } else { cout << word[dis[i]].getmean() << "\tB " << word[RandExceptNum(dis[i])].getmean() << endl; } } string tg; cin >> tg; if ((tg[0] == 'A' && !answer) || (tg[0] == 'B' && answer)) { word[dis[i]].addpro(now_user); flag[i] = 1; //标志数组置1表示答案正确 cout << "回答正确!\n" << endl; } else { word[dis[i]].reducepro(now_user); failnum++; cout << "回答错误!\n" << endl; } } if (failnum) { cout << "输入Y/y对错题进行加强:"; string xy; cin >> xy; if (xy[0] == 'Y' || xy[0] == 'y') { for (int i = 0; i < num; i++) { if (flag[i]) continue; int answer = rand() % 2; //answer == 1时答案为B 等于0时正确项为A if (rand() % 2) { cout << "第" << i + 1 << "题:" << "请选择该中文含义对应的英文:" << word[dis[i]].getmean() << ":\tA "; if (answer) { cout << word[RandExceptNum(dis[i])].getvalue() << "\tB " << word[dis[i]].getvalue() << endl; } else { cout << word[dis[i]].getvalue() << "\tB " << word[RandExceptNum(dis[i])].getvalue() << endl; } } else { cout << "第" << i + 1 << "题:" << "请选择该英文单词对应的中文:" << word[dis[i]].getvalue() << ":\tA "; if (answer) { cout << word[RandExceptNum(dis[i])].getmean() << "\tB " << word[dis[i]].getmean() << endl; } else { cout << word[dis[i]].getmean() << "\tB " << word[RandExceptNum(dis[i])].getmean() << endl; } } string tg; cin >> tg; if ((tg[0] == 'A' && !answer) || (tg[0] == 'B' && answer)) { word[dis[i]].addpro(now_user); cout << "回答正确!\n" << endl; } else { word[dis[i]].reducepro(now_user); cout << "回答错误!\n" << endl; } } } } else { cout << "没有错题,请再接再励!" << endl; } } else if (tag == 2) { for (int i = 0; i < num; i++) { cout << "第" << i + 1 << "题:" << "请输入该中文含义对应的英文:" << word[dis[i]].getmean() << ":"; string tg; cin >> tg; if (tg == word[dis[i]].getvalue()) { word[dis[i]].addpro(now_user); flag[i] = 1; cout << "回答正确!\n" << endl; } else { word[dis[i]].reducepro(now_user); failnum++; cout << "回答错误!\n" << endl; } } if (failnum) { cout << "输入Y/y对错题进行加强:"; string xy; cin >> xy; if (xy[0] == 'Y' || xy[0] == 'y') { for (int i = 0; i < num; i++) { cout << "第" << i + 1 << "题:" << "请输入该中文含义对应的英文:" << word[dis[i]].getmean() << ":"; string tg; cin >> tg; if (tg == word[dis[i]].getvalue()) { word[dis[i]].addpro(now_user); cout << "回答正确!\n" << endl; } else { word[dis[i]].reducepro(now_user); cout << "回答错误!\n" << endl; } } } } else { cout << "没有错题,请再接再励!" << endl; } } else if (tag == 3) { break; } else { cout << "你的输入有误,请重试!" << endl; } } }}
C/C++内存分区:栈、堆、全局(静态、全局)、常量区(字符串)、程序代码区
普通属性与结构体相同的内存布局。
类也可以先定义,再通过域访问操作符实现函数体。
该用户自定义函数是
用于熟悉度统计,对应功能****5 熟练度统计
图4.9 ProCalculate函数的定义
与前边部分简易的代码相比,ProCalculate函数的定义使用的两个for循环用来实现熟练度的统计,对于调用while来说简洁性和可读性较高
该用户自定义函数是
用于熟悉度查询,对应功能6 熟悉度查询
图4.10ProSearch函数的定义
ProSearch函数的定义使用了if{ }else{ for(){} }的嵌套使用。
主函数
图4.11主函数(菜单栏的定义)
五、测试数据及其结果分析
1**、用户的注册**
图5.1用户的注册
输入2 进行账号和密码的注册,根据提示所说,用户需要:
1.输入姓名(无任何限制)
2.输入想注册的账号(9位内纯数字)
3.输入登录时的密码(9位内纯数字)
4.再次输入确认密码生效
2、用户的登录
图5.2用户的登录
输入1 登录账号密码,根据提示所说,用户需要:
1.输入账号
2.输入密码
3**、登陆界面**
图5.3用户登录进入界面
登陆成功后进入界面,接下来用户根据需求输入相应的序号从而实现功能
4、功能的调试 (使用vs2022编译器)
以上六张图分别对应功能
1、单词本录入
2、单词本修改
3、单词本删除
4、背诵
6、熟练度查询
7、返回登陆
如上便是所有功能的运行结果。
六、调试过程中的问题
1、缺少头文件 #include
图6.1缺少头文件报错问题
解决办法:加上头文件 #include
2、形参不兼容
图6.2实参和形参不兼容报错问题
解决办法:
1、将结构体中定义的 char * 前面加上 "const"修饰, 按照提示将类型进行规范
2、采用将编译方式设置为ANSI:
项目->属性->项目默认值->字符集,然后把UNICODE选成多字节,重新编译
这样我们就完成了设置,并且Error得到了解决。
3、缺少声明
解决办法:补全声明即可
4、缺少未定义标识符
解决办法:同样补齐即可
七、课程设计总结
1、对于类的使用不够熟练。
2、用户自定义函数使用的不规范。
3、实参与形参的兼容性问题
4、该单词背记系统 用户数量最大只有200,单词数量最大是2000,就是数组长度,都可以改的,后续可以定义为一个常量。
5、利用cout可以输出各种数据类型的数据,可以多种方式在屏幕上显示输出信息(包括特殊符号)。
\6. 该程序完成用户的注册必须输出3.退出才能完成用户账号和密码的保存
\7. 类也可以先定义,再通过域访问操作符实现函数体。
类是用户自定义的类型,如果程序中要用到类,必须提前说明,或者使用已存在的类
(别人写好的类、标准库中的类等)
\8. 利用析构函数和数组实现对单词本词性、释义的录入、修改和删除以及单词熟悉度的统计和查询。析构函数对象消亡时被自动调用,可以定义析构函数做对象消亡时的善后工作,比如释放内存等
该代码中最难以实现的便是4 背诵,需要参考CSDN的相关博客进行修改,从而实现。
注:该试题使用的是vs2022编译器。