实验1 现代C++基础编程
任务1:
源代码task1.cpp
1 #include<iostream> 2 #include<string> 3 #include<vector> 4 #include<algorithm> 5 template<typename T> 6 void output(const T &c); 7 8 void test1(); 9 void test2(); 10 void test3() ; 11 int main() 12 { 13 std::cout<<"测试 1: \n"; 14 test1(); 15 std::cout<<"\n测试 2: \n"; 16 test2(); 17 std::cout<<"\n测试 3: \n"; 18 test3(); 19 } 20 template <typename T> 21 void output(const T &c) 22 { 23 for(auto &i: c) 24 std ::cout<<i <<' '; 25 std::cout<<'\n'; 26 } 27 28 29 void test1() 30 { 31 using namespace std; 32 string s0{"0123456789"}; 33 cout <<"s0 = "<< s0 << endl; 34 string s1(s0); 35 reverse(s1.begin(),s1.end()); 36 cout<< "s1 = "<<s1<<endl; 37 string s2(s0.size(),' '); 38 reverse_copy(s0.begin(),s0.end(),s2.begin()); 39 cout<<"s2 = "<<s2<<endl; 40 } 41 void test2() 42 { 43 using namespace std; 44 vector<int> v0{2,0,4,9}; 45 cout<<"v0: "; 46 output(v0); 47 vector<int> v1{v0}; 48 reverse(v1.begin(),v1.end()); 49 cout<<"v1: "; 50 output(v1); 51 vector<int> v2{v0}; 52 reverse_copy(v0.begin(),v0.end(),v2.begin()); 53 cout<<"v2: "; 54 output(v2); 55 } 56 void test3() 57 { 58 using namespace std; 59 vector<int> v0{0,1,2,3,4,5,6,7,8,9}; 60 cout<<"v0: "; 61 output(v0); 62 vector<int> v1{v0}; 63 rotate(v1.begin(),v1.begin()+1,v1.end()); 64 cout<<"v1: "; 65 output(v1); 66 vector<int> v2{v0}; 67 rotate(v2.begin(),v2.begin()+2,v2.end()); 68 cout<<"v2: "; 69 output(v2); 70 vector<int> v3{v0}; 71 rotate(v3.begin(),v3.end()-1,v3.end()); 72 cout<<"v3: "; 73 output(v3); 74 vector<int> v4{v0}; 75 rotate(v4.begin(),v4.end()-2,v4.end()); 76 cout<<"v4: "; 77 output(v4); 78 }
运行结果截图
(1)reverse 和reverse_copy 有什么区别?
答:reverse 将指定范围内的元素就地反转,即修改原容器(或范围)中的元素顺序。而reverse_copy虽然也是将指定范围内的元素反转,但是将结果复制到另一个容器(或范围)中,不改变原容器。
(2)rotate 算法是如何改变元素顺序的?它的三个参数分别代表什么?
答:rotate 算法执行循环左(右)移操作,将指定范围内的元素进行旋转。将 第一个参数和第三个参数范围内的元素重新排列,使得第二个参数指向的元素成为新的第一个元素,第二个参数指向的元素之前的元素移动到末尾。第一个参数:旋转范围的起始位置,第二个参数:将成为新范围第一个元素的元素位置,第三个参数:旋转范围的结束位置。
任务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 template<typename T> 10 void output(const T &c); 11 int generate_random_number(); 12 void test1(); 13 void test2(); 14 15 int main() 16 { 17 std::srand(std::time(0)); 18 std::cout<<"测试1: \n"; 19 test1(); 20 std::cout<<"测试2: \n"; 21 test2(); 22 } 23 template <typename T> 24 void output(const T &c) 25 { 26 for(auto &i:c) 27 std::cout<<i<<' '; 28 std::cout<<'\n'; 29 } 30 int generate_random_number() 31 { 32 return std::rand()%101; 33 } 34 void test1() 35 { 36 using namespace std; 37 vector<int> v0(10); 38 generate(v0.begin(),v0.end(),generate_random_number); 39 cout<<"v0: "; 40 output(v0); 41 42 vector<int> v1{v0}; 43 sort(v1.begin(),v1.end()); 44 cout<<"v1: "; 45 output(v1); 46 vector<int> v2{v0}; 47 sort(v2.begin()+1,v2.end()-1); 48 cout<<"v2: "; 49 output(v2); 50 } 51 void test2() 52 { 53 using namespace std; 54 vector<int> v0(10); 55 generate(v0.begin(),v0.end(),generate_random_number); 56 cout<<"v0: " ; 57 output(v0); 58 59 auto min_iter=min_element(v0.begin(),v0.end()); 60 auto max_iter=max_element(v0.begin(),v0.end()); 61 cout<<"最小值:"<<*min_iter<<endl; 62 cout<<"最大值:"<<*max_iter<<endl; 63 double avg1=accumulate(v0.begin(),v0.end(),0.0) /v0.size(); 64 cout<<"均值:"<<fixed<<setprecision(2)<<avg1<<endl; 65 sort(v0.begin(),v0.end()); 66 double avg2=accumulate(v0.begin()+1,v0.end()-1,0.0) /(v0.size()-2); 67 cout<<"去掉最大值、最小值之后,均值:"<<fixed<<setprecision(2)<<avg2<<endl; 68 }
运行结果截图
(1)generate 算法的作用是什么?
答:generate 算法用指定生成器函数返回的值来填充指定范围内的所有元素。在任务二中生成器函数指的是generate_random_number。
(2)minmax_element 和分别调用,min_element 、max_element 相比,有什么优势?
答:minmax_element只要遍历一次,分别调用,min_element 、max_element要遍历两次。并且minmax_element 可以保证获得的元素最大最小值在数据元素的同一状态下。
(3)把代码中函数generate_random_number 的声明(line13)和定义(line35-37)注释起来,把两处调用改成如下写法,观察效果是否等同?查阅c++中lambda表达式用法。
答:效果相同。lambda表达式适用场景:捕获局部变量,用于短小的回调函数和算法实现。
任务3:
源代码task3.cpp
1 #include<iostream> 2 #include<string> 3 #include<algorithm> 4 #include<cctype> 5 unsigned char func(unsigned char c); 6 void test1(); 7 void test2(); 8 int main() 9 { 10 std::cout<<"测试1:字符串大小转换\n"; 11 test1(); 12 std::cout<<"\n测试2:字符变换\n"; 13 test2(); 14 } 15 unsigned char func(unsigned char c) 16 { 17 if(c=='z') 18 return 'a'; 19 if(c=='Z') 20 return 'A'; 21 if(std::isalpha(c)) 22 return static_cast<unsigned char>(c+1); 23 return c; 24 } 25 void test1() 26 { 27 std::string s1{"Hello world 2049!"}; 28 std::cout<<"s1 = "<<s1<<'\n'; 29 std::string s2; 30 for(auto c:s1) 31 s2+=std::tolower(c); 32 std::cout<<"s2 = "<<s2<<'\n'; 33 std::string s3; 34 for(auto c:s1) 35 s3+=std::toupper(c); 36 std::cout<<"s3 = "<<s3<<'\n'; 37 } 38 void test2() 39 { 40 std::string s1{"I love cosmoms!"}; 41 std::cout<<"s1 = "<<s1<<'\n'; 42 std::string s2(s1.size(),' '); 43 std::transform(s1.begin(),s1.end(),s2.begin(),func); 44 std::cout<<"s2 = "<<s2<<'\n'; 45 } 46
运行结果截图
(1) 自定义函数func功能是什么?
答:这个函数的功能是对字符进行转换(后移一位,且大小写的状态保持不变):如果字符是 'z',返回 'a';如果字符是 'Z',返回 'A';如果字符是字母(但不是'z'或'Z'),则返回下一个字母(例如 'a'->'b', 'B'->'C');如果不是字母,返回原字符。
(2) tolower和toupper功能分别是什么?
答:tolower是将大写字母变成小写字母,而toupper则将小写字母变成大写字母。
(3) transform的4个参数意义分别是什么?如果把第3个参数s2.begin()改成s1.begin(),有何区别?
答:s1.begin(): 输入序列的起始迭代器,s1.end(): 输入序列的结束迭代器,s2.begin(): 输出序列的起始迭代器。func: 函数,将输入序列的每个元素通过该函数转换后存入输出序列。如果将第三个参数从s2.begin()改为s1.begin(),那么转换后的结果将会被写到s1中,使得原始输入序列发生改变。
任务4:
源代码task4.cpp
1 #include <iostream> 2 #include <string> 3 #include <algorithm> 4 bool is_palindrome(const std::string &s); 5 bool is_palindrome_ignore_case(const std::string &s); 6 int main() { 7 using namespace std; 8 string s; 9 10 while(cin >> s) { 11 cout << boolalpha 12 << "区分大小写: " << is_palindrome(s) << "\n" 13 << "不区分大小写: " << is_palindrome_ignore_case(s) << "\n\n"; 14 } 15 } 16 bool is_palindrome(const std::string &s) 17 { 18 using namespace std; 19 string s1(s); 20 reverse(s1.begin(),s1.end()); 21 if(s==s1) 22 return true; 23 else 24 return false; 25 26 } 27 bool is_palindrome_ignore_case(const std::string &s) 28 { 29 std::string s2; 30 31 for(auto c: s) 32 s2+=std::tolower(c); 33 std::string s3(s2); 34 reverse(s3.begin(),s3.end()); 35 if(s3==s2) 36 return true; 37 else 38 return false; 39 } 40
运行结果截图
(1)使用cin >> s输入时,输入的字符串中不能包含空格。如果希望测试字符串包含空格(如hello oop),代码应如何调整?
答:可以改成std::getline(std::cin, s);getline()会读取整行,包括空格,直到遇到换行符。
任务5:
源代码task5.cpp
1 #include <iostream> 2 #include <string> 3 #include <algorithm> 4 std::string dec2n(int x, int n = 2); 5 int main() { 6 int x; 7 while(std::cin >> x) { 8 std::cout << "十进制: " << x << '\n' 9 << "二进制: " << dec2n(x) << '\n' 10 << "八进制: " << dec2n(x, 8) << '\n' 11 << "十二进制: " << dec2n(x, 12) << '\n' 12 << "十六进制: " << dec2n(x, 16) << '\n' 13 << "三十二进制: " << dec2n(x, 32) << "\n\n"; 14 } 15 } 16 std::string dec2n(int x, int n) 17 { 18 std::string s; 19 int r; 20 if(x==0) 21 return "0"; 22 23 while(x>0) 24 { 25 r=x%n; 26 x/=n; 27 if(r<10) 28 s+=r+'0'; 29 else 30 s+=r+'0'+7; 31 32 } 33 reverse(s.begin(),s.end()); 34 return s; 35 36 }
运行结果截图
任务6:
源代码task6.cpp
1 #include<iostream> 2 #include<string> 3 #include<vector> 4 #include<algorithm> 5 #include<iomanip> 6 template<typename T> 7 void output(const T &c); 8 void yidong(); 9 int main() 10 { 11 yidong(); 12 13 } 14 template <typename T> 15 void output(const T &c) 16 { 17 for(auto &i : c) 18 std::cout << i << ' '; 19 std::cout << '\n'; 20 } 21 void yidong() 22 { 23 using namespace std; 24 vector<char> v0; 25 for(char c ='a';c<='z';c++) 26 v0.push_back(c); 27 cout<<setw(3)<<' '; 28 output(v0); 29 30 vector<char> v1(v0); 31 for(char &c :v1) 32 c=toupper(c) ; 33 34 for(auto i=1;i<=26;i++) 35 { 36 rotate(v1.begin(),v1.begin()+1,v1.end()); 37 cout<<setw(2)<<i<<' '; 38 output(v1); 39 } 40 }
运行结果截图
任务7
源代码task7.cpp
1 #include <iostream> 2 #include <iomanip> 3 #include <string> 4 #include <ctime> 5 6 template<typename T> 7 void output(const T &c); 8 int generate_random_number(); 9 int main() 10 { 11 std::srand(std::time(0)); 12 int canswer=0; 13 int r1,r2,op; 14 r1=std::rand()%11; 15 r2=std::rand()%11; 16 op=std::rand()%4; 17 int ca; 18 int ua; 19 for(auto i=0;i<10;i++) 20 { 21 r1=std::rand()%10+1; 22 r2=std::rand()%10+1; 23 op=std::rand()%4; 24 switch(op) 25 { 26 case 0:std::cout<<r1<<'+'<<r2<<'='; 27 ca=r1+r2; 28 break; 29 case 1: 30 while(r1<r2) 31 r2=std::rand()%10+1; 32 std::cout<<r1<<'-'<<r2<<'='; 33 ca=r1-r2; 34 break; 35 case 2:std::cout<<r1<<'*'<<r2<<'='; 36 ca=r1*r2; 37 break; 38 case 3: 39 while(r1%r2!=0) 40 r2=std::rand()%10+1; 41 std::cout<<r1<<'/'<<r2<<'='; 42 ca=r1/r2; 43 break; 44 } 45 std::cin>>ua; 46 if(ua==ca) 47 canswer++; 48 } 49 std::cout<<std::fixed <<std:: setprecision(2)<<static_cast<double>(canswer)/10*100<<'%'; 50 51 52 53 }
运行结果截图