实验1_实验报告
实验1:现代 C++ 编程初体验
四、实验结论
1. 实验任务1
运行测试截图

问题与思考
-
reverse和reverse_copy有什么区别?reverse和reverse_copy都是algorithm库中提供的算法。string通过begin和end取字符串的处理范围。
其中,reverse是在字符串的原地反转,直接修改原对象;而reverse_copy是将源字符串反转以后,放入第三个参数指定的字符串的
开头。而新的容器需要提前指定空间来存放倒置的字符串。对于vector,同样的原理,使用后者一样要提前开辟空间。
-
rotate算法是如何改变元素顺序的?它的三个参数分别代表什么?
rotate的三个参数分别是first,middle,last,其实质是迭代器(类似于指针,指向元素的位置)。rotate将first-middle,middle-last的元素进行反转。如果追究内部的实现,可以理解成1)在first-middle内部,middle-last内部分别进行反转,然后在整体first-last反转。如果形象理解三个参数的话,分别可以是:旋转范围的起点,旋转后第一个元素的位置,旋转范围的终点
2. 实验任务2
运行测试截图

问题与思考
-
generate算法的作用是什么?generate算法根据三个参数:生成的起始和终止位置,以及用于生成的函数。通过生成函数的返回值,在指定的容器的范围内生成元素。
-
minmax_element和分别调用min_element、max_element相比,有什么优势?
前者只需要一次便遍历,同时取得了最大最小值对应元素的迭代器,然后用迭代器皆因用得到最终元素。这样的效率更高,相当于把最大最小的迭代器组成了pair,在结构上也便于对问题的理解,简化了程序。 -
与自定义函数
generate_random_number相比,lambda 表达式适合什么场景?
lambda表达式直接写在使用位置且没有名称,相当于嵌入代码上下文逻辑的一个函数体。
这种嵌入的架构带来便利也就是:只使用一次、代码较短、逻辑比较简单的场景使用非常简练,而且lambda还可以通过[]捕获列表,直接在代码块内部捕获参数值甚至通过&引用来在代码块内部修改参数。如果整个代码的思路是一体的,那么使用lambda表达式非常合适,方便且符合理解的逻辑。相比generate_random_number这样在外部声明的函数可复用,具有解耦的特性,lambda更加简洁快速,而且便于集成。
3. 实验任务3
运行测试截图

问题与思考
-
自定义函数
func的功能是什么?
func中,一般情况下,使用isalpha(包含在cctype中)判断输入是否是字符。unsigned char是为了让所有字节都保持非负,并能够传递给isalpha。
对于字母表的结尾Z,z需要进行循环转换的补充。这样实现了字符向后变换一个的功能。
-
tolower和toupper的功能分别是什么?分别将字符转换成对应的小写、大写形式。
-
transform的4个参数的意义分别是什么?如果把第3个参数s2.begin()改成s1.begin(),有何区别?第一、二个参数代表原始数据的范围,第三个参数代表转换后的对象放入的容器的开始位置,第四个参数代表转换使用的函数
操作发现,如果改动,那么s2输出为空,s1输出为转换后的对象。应证了对于第三个参数意义的判断,此时s1转换后的对象又存入s1。
4. 实验任务4
源代码
bool is_palindrome(const std::string &s) {
(void)s;
using namespace std;
string s1(s);
reverse(s1.begin(),s1.end());
return s1==s;
}
bool is_palindrome_ignore_case(const std::string &s) {
(void)s;
using namespace std;
string s1(s);
string s2(s);
transform(s1.begin(),s1.end(),s1.begin(),::tolower);
reverse(s1.begin(),s1.end());
transform(s2.begin(),s2.end(),s2.begin(),::tolower);
return s1==s2;
}
运行测试截图

问题与思考
使用 cin >> s 时无法输入含空格的字符串。如果需要测试 hello oop,代码应如何调整?
可以使用getline(cin,s)来读取包含空格的输入
while (getline(cin, s)) {

5. 实验任务5
源代码
std::string dec2n(int x, int n) {
(void)x;
(void)n;
using namespace std;
if(x==0){
return "0";
}
if(n<2||n>36){
throw logic_error("进制数n必须在[2,36]区间内");
}
vector<int> v;
vector<char> v1;
while(x>0){
v.push_back(x%n);
x/=n;
}
while(!v.empty()){
int i = v.back();
v.pop_back();
if(i>=10){
v1.push_back(static_cast<char>('A'+i-10));
}else{
v1.push_back(static_cast<char>('0'+i));
}
}
return string(v1.begin(),v1.end());
}
运行测试截图

6. 实验任务6
源代码
#include <iostream>
using namespace std;
void printcode();
int main() {
printf(" ");
for(char i='a';i<='z';i++)
{
printf("%2c",i);
}
printf("\n");
printcode();
return 0;
}
void printcode()
{
vector<char> v(26);
for(int i=0;i<26;i++)
{
v[i]='A'+i;
}
for(int i=1;i<=26;i++)
{
rotate(v.begin(),v.begin()+1,v.end());
printf("%2d",i);
for(int j=0;j<26;j++)
{
printf("%2c",v[j]);
}
printf("\n");
}
return;
}
运行测试截图

7. 实验任务7
源代码
#include <cstdlib>
#include <ctime>
#include <iomanip>
#include <iostream>
using namespace std;
int main() {
// TODO(学生): 完成10道随机四则运算题的生成、输入、评测和正确率输出。
// 要求摘要:
// - 操作数为 [1, 10] 的整数,运算符为 + - * /。
// - 减法的第一个操作数 >= 第二个操作数。
// - 除法必须整除。
// - 正确率以百分数输出,保留两位小数。
// - 可用 std::srand(std::time(nullptr)) 设置随机种子。
int count = 0;
for(int i=0;i<10;i++)
{
srand(time(nullptr));
int a = rand()%10+1;
int b = rand()%10+1;
int op = rand()%4;
int ans;
char op_char;
switch (op) {
case 0:
ans = a + b;
op_char = '+';
break;
case 1:
if (a < b) {
swap(a, b);
}
ans = a - b;
op_char = '-';
break;
case 2:
ans = a * b;
op_char = '*';
break;
case 3: {
b = rand() % 10 + 1;
int q = rand() % (10 / b) + 1;
a = b * q;
//10/b表示最大商,+1表示从1开始,然后同样得到在最大商到1的随机数
ans = q;
op_char = '/';
break;
}
}
cout << "第" << i + 1 << "题: " << a << ' ' << op_char << ' ' << b << " = ";
int user_ans;
cin >> user_ans;
if (user_ans == ans) {
count++;
}
}
printf("正确率: %.2f%%\n", (count / 10.0) * 100);
}
运行测试截图

五、实验总结
1.学习到了新的概念:迭代器,rotate,reverse,reverse_copy通过迭代器实现容器内元素的变换
2.task5:结合数据结构课上学到的栈先进先出的特点,使用栈完成了进制转换的实现。但是仍有疑问:是不是可以不使用整个容器进行存储,直接将输出拼接到字符串的末尾呢?源代码开了两个vector是否有必要?
3.task7:在实现除法出题时,考虑还可以把所有情况进行枚举,因为数据量很小

浙公网安备 33010602011771号