实验1 现代C++编程初体验
task1:
源代码task1.cpp
1 // 现代C++标准库、算法库体验 2 // 本例用到以下内容: 3 // 1. 字符串string, 动态数组容器类vector、迭代器 4 // 2. 算法库:反转元素次序、旋转元素 5 // 3. 函数模板、const引用作为形参 6 #include <iostream> 7 #include <string> 8 #include <vector> 9 #include <algorithm> 10 // 模板函数声明 11 template<typename T> 12 void output(const T &c); 13 void test1(); 14 void test2(); 15 void test3(); 16 int main() { 17 std::cout << "测试1: \n"; 18 test1(); 19 std::cout << "\n测试2: \n"; 20 test2(); 21 std::cout << "\n测试3: \n"; 22 test3(); 23 } 24 // 输出容器对象c中的元素 25 template <typename T> 26 void output(const T &c) { 27 for(auto &i : c) 28 std::cout << i << ' '; 29 std::cout << '\n'; 30 } 31 // 测试1:组合使用算法库、迭代器、string反转字符串 32 void test1() { 33 using namespace std; 34 string s0{"0123456789"}; 35 cout << "s0 = " << s0 << endl; 36 string s1(s0); 37 // 反转s1自身 38 reverse(s1.begin(), s1.end()); 39 cout << "s1 = " << s1 << endl; 40 string s2(s0.size(), ' '); 41 // 将s0反转后结果拷贝到s2, s0自身不变 42 reverse_copy(s0.begin(), s0.end(), s2.begin()); 43 cout << "s2 = " << s2 << endl; 44 } 45 // 测试2:组合使用算法库、迭代器、vector反转动态数组对象vector内数据 46 void test2() { 47 using namespace std; 48 vector<int> v0{2, 0, 4, 9}; 49 cout << "v0: "; output(v0); 50 vector<int> v1{v0}; 51 reverse(v1.begin(), v1.end()); 52 cout << "v1: "; output(v1); 53 vector<int> v2{v0}; 54 reverse_copy(v0.begin(), v0.end(), v2.begin()); 55 cout << "v2: "; output(v2); 56 } 57 // 测试3:组合使用算法库、迭代器、vector实现元素旋转移位 58 void test3() { 59 using namespace std; 60 vector<int> v0{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; 61 cout << "v0: "; output(v0); 62 vector<int> v1{v0}; 63 // 将[v1.begin(), v1.end())区间内元素循环左移1位 64 rotate(v1.begin(), v1.begin()+1, v1.end()); 65 cout << "v1: "; output(v1); 66 vector<int> v2{v0}; 67 // 将[v1.begin(), v1.end())区间内元素循环左移2位 68 rotate(v2.begin(), v2.begin()+2, v2.end()); 69 cout << "v2: "; output(v2); 70 vector<int> v3{v0}; 71 // 将[v1.begin(), v1.end())区间内元素循环右移1位 72 rotate(v3.begin(), v3.end()-1, v3.end()); 73 cout << "v3: "; output(v3); 74 vector<int> v4{v0}; 75 // 将[v1.begin(), v1.end())区间内元素循环右移2位 76 rotate(v4.begin(), v4.end()-2, v4.end()); 77 cout << "v4: "; output(v4); 78 }
运行结果截图:
观察与思考:
问题1: reverse 和 reverse_copy 有什么区别?
ans:reverse是直接反转自身,revers_copy是将反转的结果赋值给另一个对象,自身不改变
问题2: rotate 算法是如何改变元素顺序的?它的三个参数分别代表什么?
ans:工作原理是将容器看成一个环然后进行循环搬运。三个参数分别代表循环起点,序列新起点,循环终点
task2
源代码task2.cpp
1 #include <iostream> 2 #include <vector> 3 #include <algorithm> 4 #include <numeric> 5 #include <iomanip> 6 #include <cstdlib> 7 #include <ctime> 8 // 模板函数声明 9 template<typename T> 10 void output(const T &c); 11 int generate_random_number(); 12 void test1(); 13 void test2(); 14 int main() { 15 std::srand(std::time(0)); // 添加随机种子 16 std::cout << "测试1: \n"; 17 test1(); 18 std::cout << "\n测试2: \n"; 19 test2(); 20 } 21 // 输出容器对象c中的元素 22 template <typename T> 23 void output(const T &c) { 24 for(auto &i: c) 25 std::cout << i << ' '; 26 std::cout << '\n'; 27 } 28 // 返回[0, 100]区间内的一个随机整数 29 int generate_random_number() { 30 return std::rand() % 101; 31 } 32 // 测试1:对容器类对象指定迭代器区间赋值、排序 33 void test1() { 34 using namespace std; 35 vector<int> v0(10); // 创建一个动态数组对象v0, 对象大小为10 36 generate(v0.begin(), v0.end(), generate_random_number); // 生成随机数填充v0 37 cout << "v0: "; output(v0); 38 vector<int> v1{v0}; 39 sort(v1.begin(), v1.end()); // 对整个vector排序 40 cout << "v1: "; output(v1); 41 vector<int> v2{v0}; 42 sort(v2.begin()+1, v2.end()-1); // 只对中间部分排序,不包含首尾元素 43 cout << "v2: "; output(v2); 44 } 45 // 测试2:对容器类对象指定迭代器区间赋值、计算最大值/最小值/均值 46 void test2() { 47 using namespace std; 48 vector<int> v0(10); 49 generate(v0.begin(), v0.end(), generate_random_number); 50 cout << "v0: "; output(v0); 51 // 求最大值和最小值 52 auto min_iter = min_element(v0.begin(), v0.end()); 53 auto max_iter = max_element(v0.begin(), v0.end()); 54 cout << "最小值: " << *min_iter << endl; 55 cout << "最大值: " << *max_iter << endl; 56 // 同时求最大值和最小值 57 auto ans = minmax_element(v0.begin(), v0.end()); 58 cout << "最小值: " << *(ans.first) << endl; 59 cout << "最大值: " << *(ans.second) << endl; 60 // 求平均值 61 double avg1 = accumulate(v0.begin(), v0.end(), 0.0) / v0.size(); 62 cout << "均值: " << fixed << setprecision(2) << avg1 << endl; 63 sort(v0.begin(), v0.end()); 64 double avg2 = accumulate(v0.begin()+1, v0.end()-1, 0.0) / (v0.size()-2); 65 cout << "去掉最大值、最小值之后,均值: " << avg2 << endl; 66 }
运行结果截图:
观察与思考:
问题1: generate 算法的作用是什么?
ans:依次将一个随机数赋值给一个容器里的元素
问题2: minmax_element 和分别调用 min_element 、 max_element 相比,有什么优势?
ans:减少代码行数;只用遍历一次,提高代码性能
问题3:查询 generate 第3个参数 [](){return std::rand()%101;} 用法,与使用自定义函数
generate_random_number 相比,lambda表达式适用场景是什么?
ans:效果相同,lambda适用场景为适合几行到十几行的简单逻辑,在定义的地方附近使用
task3
源代码task3.cpp
1 #include <iostream> 2 #include <string> 3 #include <algorithm> 4 #include <cctype> 5 6 unsigned char func(unsigned char c); 7 8 void test1(); 9 void test2(); 10 11 int main() 12 { 13 std::cout << "测试1: 字符串大小写转换\n"; 14 test1(); 15 std::cout << "\n测试2: 字符变换\n"; 16 test2(); 17 } 18 19 unsigned char func(unsigned char c) 20 { 21 if (c == 'z') 22 return 'a'; 23 if (c == 'Z') 24 return 'A'; 25 if (std::isalpha(c)) 26 return static_cast<unsigned char>(c + 1); 27 return c; 28 } 29 30 void test1() 31 { 32 std::string s1{"Hello World 2049!"}; 33 std::cout << "s1 = " << s1 << '\n'; 34 std::string s2; 35 for (auto c : s1) 36 s2 += std::tolower(c); 37 std::cout << "s2 = " << s2 << '\n'; 38 std::string s3; 39 for (auto c : s1) 40 s3 += std::toupper(c); 41 std::cout << "s3 = " << s3 << '\n'; 42 } 43 44 void test2() 45 { 46 std::string s1{"I love cosmos!"}; 47 std::cout << "s1 = " << s1 << '\n'; 48 std::string s2(s1.size(), ' '); 49 std::transform(s1.begin(), s1.end(), s2.begin(), func); 50 std::cout << "s2 = " << s2 << '\n'; 51 }
运行结果截图:
观察与思考:
问题1:自定义函数 func 功能是什么?
ans:func
函数实现了一个字符移位加密功能,相当于每个字母向后移动一位,实现简单的凯撒密码加密
问题2: tolower 和 toupper 功能分别是什么?
ans:std::tolower
:将字符转换为小写形式;std::toupper
:将字符转换为大写形式
问题3: transform 的4个参数意义分别是什么?如果把第3个参数 s2.begin() 改成 s1.begin() ,有何区
别?
ans:输入范围的起始迭代器,输入范围的结束迭代器,输出范围的起始迭代器,转换函数(对每个元素应用的操作);一个是转换到新容器,一个是原地转换
task4
源代码task4.cpp
1 #include <iostream> 2 #include <string> 3 #include <algorithm> 4 5 bool is_palindrome(const std::string &s); 6 bool is_palindrome_ignore_case(const std::string &s); 7 8 int main() 9 { 10 using namespace std; 11 string s; 12 // 多组输入,直到按下Ctrl+Z结束测试 13 while (cin >> s) 14 { 15 cout << boolalpha 16 << "区分大小写: " << is_palindrome(s) << "\n" 17 << "不区分大小写: " << is_palindrome_ignore_case(s) << "\n\n"; 18 } 19 } 20 21 // 函数is_palindrome定义 22 bool is_palindrome(const std::string &s){ 23 using namespace std; 24 string reversed = s; 25 reverse(reversed.begin(), reversed.end()); 26 return s == reversed; 27 } 28 // 函数is_palindrome_ignore_case定义 29 bool is_palindrome_ignore_case(const std::string &s){ 30 using namespace std; 31 32 string lower_str; 33 lower_str.resize(s.size()); 34 transform(s.begin(), s.end(), lower_str.begin(),[](unsigned char c) { return tolower(c); }); 35 36 string reversed_lower = lower_str; 37 reverse(reversed_lower.begin(), reversed_lower.end()); 38 39 return lower_str == reversed_lower; 40 }
运行结果截图:
观察与思考:
问题:使用 cin >> s 输入时,输入的字符串中不能包含空格。如果希望测试字符串包含空格(如 hello
oop ),代码应如何调整?
ans:使用std::getline
task5
源代码task5.cpp
1 #include <iostream> 2 #include <string> 3 #include <algorithm> 4 5 std::string dec2n(int x, int n = 2); 6 7 int main() 8 { 9 int x; 10 while (std::cin >> x) 11 { 12 std::cout << "十进制: " << x << '\n' 13 << "二进制: " << dec2n(x) << '\n' 14 << "八进制: " << dec2n(x, 8) << '\n' 15 << "十二进制: " << dec2n(x, 12) << '\n' 16 << "十六进制: " << dec2n(x, 16) << '\n' 17 << "三十二进制: " << dec2n(x, 32) << "\n\n"; 18 } 19 } 20 21 // 函数dec2n定义 22 std::string dec2n(int x,int n){ 23 using namespace std; 24 if(x==0){ 25 return "0"; 26 } 27 string transx; 28 string s="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 29 while(x!=0){ 30 transx+=s[x%n]; 31 x/=n; 32 } 33 reverse(transx.begin(),transx.end()); 34 return transx; 35 }
运行结果截图:
task6
源代码task6.cpp
1 #include<bits/stdc++.h> 2 int main(){ 3 using namespace std; 4 string origin="ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 5 cout<<" a b c d e f g h i j k l m n o p q r s t u v w x y z"<<endl; 6 for(int i=1;i<=26;i++){ 7 rotate(origin.begin(),origin.begin()+1,origin.end()); 8 cout<<setw(2)<<i; 9 for(auto c:origin){ 10 cout<<" "<<c; 11 } 12 cout<<endl; 13 } 14 return 0; 15 }
运行结果截图:
task7
源代码task7.cpp
1 #include<bits/stdc++.h> 2 3 int GenerateNum(){ 4 return(rand()%10)+1; 5 } 6 7 char GenerateChar(){ 8 using namespace std; 9 string c="+-*/"; 10 int index= rand()%4; 11 return c[index]; 12 } 13 14 int main(){ 15 using namespace std; 16 srand(time(0)); 17 int count=0,correct=0; 18 19 while(count<10){ 20 int a,b,c,userAnswer; 21 char sign; 22 a=GenerateNum(); 23 b=GenerateNum(); 24 sign=GenerateChar(); 25 if(sign=='+'){ 26 c=a+b; 27 } 28 if(sign=='-'){ 29 c=a-b; 30 } 31 if(sign=='*'){ 32 c=a*b; 33 } 34 if(sign=='/'){ 35 c=a/b; 36 } 37 if(c<0){ 38 continue; 39 } 40 if(a%b!=0){ 41 continue; 42 } 43 cout<<a<<sign<<b<<"="; 44 cin>>userAnswer; 45 if(userAnswer==c){ 46 correct++; 47 } 48 count++; 49 } 50 double percentCorrect=static_cast<double>(correct)/10*100; 51 52 cout<<"正确率:"<< fixed<<setprecision(2)<<percentCorrect<<"%"<<endl; 53 return 0; 54 }
运行结果截图: