实验1 现代C++编程初体验
任务1:
task1.cpp
1 //现代C++标准库、算法库体验 2 //本例用到如下内容: 3 //1.字符串string,动态数组容器类vector、迭代器 4 //2.算法库:反转元素次序、旋转元素 5 //3.函数模板、const引用作为形参 6 7 #include<iostraem> 8 #include<string> 9 #include<vector> 10 #include<algorithm> 11 12 //模板函数声明 13 template<typename T> 14 void output(const T &c); 15 16 void test1(); 17 void test2(); 18 void test3(); 19 20 int main() { 21 std::cout << "测试1:\n"; 22 test1(); 23 24 std::cout << "测试2:\n"; 25 test2(); 26 27 std::cout << "测试3:\n"; 28 test3(); 29 } 30 31 //输出容器对象c中的元素 32 template<typename T> 33 void output(const T &c) { 34 for(auto &i:c) 35 std::cout << i << ' '; 36 std::cout << "\n"; 37 } 38 39 //测试1:组合使用算法库、迭代器、string反转字符串 40 void test1() { 41 using namespace std; 42 43 string s0{"0123456789"}; 44 cout << "s0 = " << s0 << endl; 45 46 string s1(s0); 47 //反转s1自身 48 reverse(s1.begin(),s1.end()); 49 cout << "s1 = " << s1 << endl; 50 51 string s2(s0.size(),' '); 52 //将s0反转后结果拷贝到s2,s0自身不变 53 reverse_copy(s0.begin(),s0.end(),s2.begin()); 54 cout << "s2 = " << s2 << endl; 55 } 56 57 //测试2:组合使用算法库、迭代器、vector反转动态数组对象vector内数据 58 void test2() { 59 using namespace std; 60 61 vector<int> v0{2,0,4,9}; 62 cout << "v0:"; 63 output(v0); 64 65 vector<int> v1{v0}; 66 reverse(v1.begin(),v1.end()); 67 cout << "v1:"; 68 output(v1); 69 70 vector<int> v2{v0}; 71 reverse_copy(v0.begin(),v0.end(),v2.begin()); 72 cout << "v2:"; 73 output(v2); 74 } 75 76 //测试3:组合使用算法库、迭代器、vector实现元素旋转移位 77 void test3() { 78 using namespace std; 79 80 vector<int> v0{0,1,2,3,4,5,6,7,8,9}; 81 cout << "v0:"; 82 output(v0); 83 84 vector<int> v1{v0}; 85 //将[v1.begin(),v1.end()]区间内元素循环左移1位 86 rotate(v1.begin(),v1.begin()+1,v1.end()); 87 cout << "v1:"; 88 output(v1); 89 90 vector<int> v2{v0}; 91 //将[v2.begin(),v2.end()]区间内元素循环左移2位 92 rotate(v2.begin(),v2.begin()+2,v2.end()); 93 cout << "v2:"; 94 output(v2); 95 96 vector<int> v3{v0}; 97 //将[v3.begin(),v3.end()]区间内元素循环右移1位 98 rotate(v3.begin(),v3.end()-1,v3.end()); 99 cout << "v3:"; 100 coutput(v3); 101 102 vector<int> v4{v0}; 103 //将[v4.begin(),v4.end()]区间内元素循环右移2位 104 rotate(v4.begin(),v4.end()-2,v4.end()); 105 cout << "v4:"; 106 output(v4); 107 }
# reverse和reverse_copy有什么区别?
reverse 直接将动态数组反转;
reverse_copy 不能修改原动态数组,将反转的结果复制到另一个动态数组;
## rotate算法是如何改变元素顺序的?它的三个参数分别代表什么?
rotate(T first,T n_first,T last):将n_first到last之间的元素剪下来,贴到frist前面;
first代表范围的起始位置,n_first代表要旋转到前面的元素的位置,last代表范围的结束位置。
任务2:
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 //模板函数声明 10 template<typename T> 11 void output(const T &c); 12 13 int generate_random_number(); 14 void test1(); 15 void test2(); 16 17 int main() { 18 std::srand(std::time(0)); //添加随机种子 19 std::cout << "测试1:\n"; 20 test1(); 21 22 std::cout << "测试2:\n"; 23 test2(); 24 } 25 26 //输出容器对象c中的元素 27 template<typename T> 28 void output(const T &c) { 29 for(auto &i:c) 30 std::cout << i << " "; 31 std::cout << "\n"; 32 }
1 //返回[0,100]区间内的一个随机整数 2 int generate_random_number() { 3 return std::rand() % 101; 4 } 5 6 //测试1:对容器类对象指定迭代器区间赋值、排序 7 void test1() { 8 using namespace std; 9 10 vector<int> v0(10); //创建一个动态数组对象v0,对象大小为10 11 generate(v0.begin(),v0.end(),generate_random_number); //生成随机数填充v0 12 cout << "v0:"; 13 output(v0); 14 15 vector<int> v1{v0}; 16 sort(v1.begin(),v1.end()); //对整个vector排序 17 cout << "v1:"; 18 output(v1); 19 20 vector<int> v2{v0}; 21 sort(v2.begin()+1,v2.end()-1); //只对中间部分排序,不包含首尾元素 22 cout << "v2:"; 23 output(v2); 24 } 25 26 //测试2:对容器对象指定迭代器区间赋值,计算最大值/最小值/均值 27 void test2() { 28 using namespace std; 29 30 vector<int> v0(10); 31 generate(v0.begin(),v0.end(),generate_random_number); 32 cout << "v0:"; 33 output(v0); 34 35 //求最大值和最小值 36 auto min_iter = min_element(v0.begin(),v0.end()); 37 auto max_iter = max_element(v0.begin(),v0.end()); 38 cout << "最小值:" << *min_iter << endl; 39 cout << "最大值:" << *max_iter << endl; 40 41 //求平均值 42 double avg1 = accumulate(v0.begin(),v0.end(),0.0) / v0.size(); 43 cout << "均值:" << fixed << setprecision(2) << avg1 << endl; 44 45 sort(v0.begin(),v0.end()); 46 double avg2 = accumulate(v0.begin()+1,v0.end()-1,0.0) / (v0.size()-2); 47 cout << "去掉最大值、最小值之后,均值:" << avg2 << endl; 48 }
#generate算法的作用是什么?
用指定的随机生成函数generate_random_number填充区间(v0.begin(),v0.end())。
##minmax_element和分别调用min_element、max_element相比,有什么优势?
性能更好:分别调用需要遍历两次v0数组,而直接用minmax_element调用则只用遍历1次;
代码更简洁;
###generate_random_number 的声明(line13)和定义(line35-37)注释起来,把两处调用改成如 下写法,观察效果是否等同?查阅c++中lambda表达式用法。
1 //test1()模块和 test2()模块: 2 generate(v0.begin(),v0.end,generate_random_number); 3 ---->改成 4 generate()v0.begin(),v0.end(),[](){return std::rand%101;});
效果相同;
Lambda基本语法:[捕获列表](参数列表) -> 返回类型{ 函数体 }
[ ]() {return rand() % 101;} //无参数,无捕获
[ ](int x){ return x * 2;} //带参数
[=]() {return external_var;} //值捕获所有外部变量
[&]() {external_var++;} //引用捕获所有外部变量
[var1,&var2]() {return var1 + var2;} // 混合捕获
任务3:
task3.cpp
1 #include<iostream> 2 #include<string> 3 #include<algorithm> 4 #include<cctype> 5 6 unsigned char func(unsigned char c); 7 void test1(); 8 void test2(); 9 10 int main() { 11 std::cout << "测试1:字符串大小写转换\n"; 12 test1(); 13 14 std::cout << "\n测试2:字符变换\n"; 15 test2(); 16 } 17 18 unsigned char func(unsigned char c) { 19 if(c == 'z') 20 return 'a'; 21 if(c == 'Z') 22 return 'A'; 23 24 if(std::isalpha(c)) 25 return static_cast<unsigned char>(c+1); 26 27 return c; 28 } 29 30 void test1() { 31 std::string s1{"HELLO World 2049!"}; 32 std::cout << "s1 = " << s1 << "\n"; 33 34 std::string s2; 35 for(auto c : s1) 36 s2 += std::tolower(c); 37 std::cout << "s2 = " << s2 << "\n"; 38 39 std::string s3; 40 for(auto c : s1) 41 s3 += std::toupper(c); 42 std::cout << "s3 = " << s3 << "\n"; 43 } 44 45 void test2() { 46 std::string s1{"I love cosmos!"}; 47 std::cout << "s1 = " << s1 << "\n"; 48 49 std::string s2(s1.size(),' '); 50 std::transform(s1.begin(),s1.end(),s2.begin(),func); 51 std::cout << "s2 = " << s2 << "\n"; 52 }
#自定义函数func功能是什么?
将字母字符变成它的下一个字母字符。
##tolower和toupper功能分别是什么?
tolower:将字符转换成小写;
toupper:将字符转换成大写;
###transform的4个参数意义分别是什么?如果把第3个参数s2.begin()改成s1.begin(),有何区别?
第一个s1.begin()表示输入范围的开始,第二个s2.end()表示输入范围的结束,第三个s2.begin()表示输出位置的开始,第四个func表示对每个字符应用func函数;
若修改,则对字符应用func函数后,会覆盖s1的原位置,将处理结果存储在s1中。
任务4:
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 using namespace std; 10 string s; 11 12 //多组输入,直到按下Ctrl+Z结束测试 13 while(cin >> s) { 14 cout << boolalpha 15 << "区分大小写:" << is_palindrome(s) << "\n" 16 << "不区分大小写:" << is_palindrome_ignore_case(s) << "\n\n"; 17 } 18 } 19 20 //函数is_palindrome的定义 21 bool is_palindrome(const std::string &s) { 22 std::string s1(s.size(),' '); 23 std::reverse_copy(s.begin(),s.end(),s1.begin()); 24 if(s == s1) 25 return true; 26 else 27 return false; 28 } 29 #include<cctype> 30 //函数is_palindrome_ignore_case的定义 31 bool is_palindrome_ignore_case(const std::string &s) { 32 std::string s1(s.size(),' '); 33 std::string s2{s}; 34 std::reverse_copy(s.begin(),s.end(),s1.begin()); 35 for(auto &i:s1) {i = std::tolower(i);} 36 for(auto &i:s2) {i = std::tolower(i);} 37 if(s1 == s2) 38 return true; 39 else 40 return false; 41 }
#使用cin >> s输入时,输入的字符串中不能包含空格。如果希望测试字符串包含空格(如hello oop),代码应如何调整?
可将while(cin >> s)换成while(getline(cin,s)),此时若s为空字符串或者读到'\n'结束。
任务5:
task5.cpp
1 #include <iostream> 2 #include<string> 3 #include<algorithm> 4 5 std::string dec2n(int x, int n = 2); 6 int main() { 7 int x; 8 while(std::cin >> x) { 9 std::cout << "十进制: " << x << '\n' 10 << "二进制: " << dec2n(x) << '\n' 11 << "八进制: " << dec2n(x, 8) << '\n' 12 << "十二进制: " << dec2n(x, 12) << '\n' 13 << "十六进制: " << dec2n(x, 16) << '\n' 14 << "三十二进制: " << dec2n(x, 32) << "\n\n"; 15 } 16 } 17 18 //函数dec2n定义 19 std::string dec2n(int x,int n) { 20 if(x == 0) 21 return "0"; 22 const std::string dict{"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"}; 23 std::string s; 24 while(x > 0) { 25 int i = x%n; 26 x /= n; 27 s += dict[i]; 28 } 29 std::reverse(s.begin(),s.end()); 30 return s; 31 }
任务6:
task6.cpp
1 #include<iostream> 2 #include<string> 3 #include<iomanip> 4 #include<algorithm> 5 6 int main() { 7 std::string s1{"abcdefghijklmnopqrstuvwxyz"}; 8 std::string s2{"ABCDEFGHIJKLMNOPQRSTUVWXYZ"}; 9 std::cout << " "; 10 for(const auto &i:s1) 11 std::cout << i << " "; 12 std::cout << "\n"; 13 for(int i=1;i<=26;i++) { 14 std::cout << std::setw(2) << i << " "; 15 rotate(s2.begin(),s2.begin()+1,s2.end()); 16 for(const auto &j:s2) 17 std::cout << j << " "; 18 std::cout << "\n"; 19 } 20 }
任务7:
task7.cpp
1 #include<iostream> 2 #include<ctime> 3 #include<string> 4 #include<algorithm> 5 #include<iomanip> 6 7 int generate_random_number(); 8 int random_number(); 9 10 int main() { 11 std::srand(time(0)); 12 std::string symbol{"+-*/"}; 13 double count = 0.0; 14 15 for(int i = 0;i < 10;i++) { 16 int number1 = generate_random_number(); 17 int number2 = generate_random_number(); 18 int number = random_number(); 19 int answer; 20 21 if(number == 0) { 22 std::cout << number1 << " " << symbol[number] << 23 " " << number2 << " = "; 24 std::cin >> answer; 25 if(answer == number1 + number2) 26 count++; 27 std::cout << "\n"; 28 } 29 else if(number == 1) { 30 if(number1 < number2) 31 std::swap(number1,number2); 32 std::cout << number1 << " " << symbol[number] << 33 " " << number2 << " = "; 34 std::cin >> answer; 35 if(answer == number1 - number2) 36 count++; 37 std::cout << "\n"; 38 } 39 else if(number == 2) { 40 std::cout << number1 << " " << symbol[number] << 41 " " << number2 << " = "; 42 std::cin >> answer; 43 if(answer == number1 * number2) 44 count++; 45 std::cout << "\n"; 46 } 47 if(number == 3) { 48 while(number1 % number2 != 0) { 49 if(number2 % number1 != 0) { 50 number1 = generate_random_number(); 51 number2 = generate_random_number(); 52 continue; 53 } 54 if(number1 < number2) 55 std::swap(number1,number2); 56 } 57 std::cout << number1 << " " << symbol[number] << 58 " " << number2 << " = "; 59 std::cin >> answer; 60 if(answer == number1 / number2) 61 count++; 62 std::cout << "\n"; 63 } 64 } 65 66 std::cout << "正确率:" << std::fixed << std::setprecision(2) 67 << count*10 << "%" <<std::endl; 68 } 69 70 int generate_random_number() { 71 return std::rand() % 11; 72 } 73 int random_number() { 74 return std::rand() % 4; 75 }
###实验总结###
通过这次实践,我对C++运用更加熟悉了一些,对于一些库函数的用法更加熟悉了,对于解决一些问题,我开始转变C语言思路,尽量尝试用我不熟悉的C++编写,通过这次实验,我也发现了C++语言的一些优势之处,例如数组元素的移动、求最大最小值。这些收获让我欣喜的同时,我也深刻体会到了C++内容的广阔,期待着以后进一步的学习。