一、实验任务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 void test1(); 8 void test2(); 9 void test3(); 10 int main(){ 11 std::cout<<"测试1:\n"; 12 test1(); 13 std::cout<<"\n测试2:\n"; 14 test2(); 15 std::cout<<"\n测试3:\n"; 16 test3(); 17 } 18 template<typename T> 19 void output(const T&c){ 20 for(auto &i:c) 21 std::cout<<i<<' '; 22 std::cout<<'\n'; 23 } 24 void test1(){ 25 using namespace std; 26 string s0{"0123456789"}; 27 cout<<"s0="<<s0<<endl; 28 29 string s1(s0); 30 reverse(s1.begin(),s1.end()); 31 cout<<"s1="<<s1<<endl; 32 33 string s2(s0.size(),' '); 34 reverse_copy(s0.begin(),s0.end(),s2.begin()); 35 cout<<"s2="<<s2<<endl; 36 } 37 void test2(){ 38 using namespace std; 39 vector<int> v0{2,0,4,9}; 40 cout<<"v0:"; 41 output(v0); 42 43 vector<int> v1{v0}; 44 reverse(v1.begin(),v1.end()); 45 cout<<"v1:"; 46 output(v1); 47 48 vector<int> v2{v0}; 49 reverse_copy(v0.begin(),v0.end(),v2.begin()); 50 cout<<"v2:"; 51 output(v2); 52 } 53 void test3(){ 54 using namespace std; 55 vector<int> v0{0,1,2,3,4,5,6,7,8,9}; 56 cout<<"v0:"; 57 output(v0); 58 59 vector<int> v1{v0}; 60 rotate(v1.begin(),v1.begin()+1,v1.end()); 61 cout<<"v1:"; 62 output(v1); 63 64 vector<int> v2{v0}; 65 rotate(v2.begin(),v2.begin()+2,v2.end()); 66 cout<<"v2:"; 67 output(v2); 68 69 vector<int> v3{v0}; 70 rotate(v3.begin(),v3.end()-1,v3.end()); 71 cout<<"v3:"; 72 output(v3); 73 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函数是让string、vector等容器内的元素进行反转,会直接改变容器内元素的顺序;而reverse_copy函数虽然同样可以使string、vector等容器内的元素进行反转,但会将反转后的元素拷贝到新容器中,对自身的元素顺序没有影响。
问题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 template<typename T> 9 void output(const T&c); 10 int generate_random_number(); 11 void test1(); 12 void test2(); 13 int main(){ 14 std::srand(std::time(0)); 15 std::cout<<"测试1:\n"; 16 test1(); 17 std::cout<<"\n测试2:\n"; 18 test2(); 19 } 20 template <typename T> 21 void output(const T&c){ 22 for(auto &i:c) 23 std::cout<<i<<' '; 24 std::cout<<'\n'; 25 } 26 int generate_random_number(){ 27 return std::rand()%101; 28 } 29 void test1(){ 30 using namespace std; 31 vector<int> v0(10); 32 generate(v0.begin(),v0.end(),generate_random_number); 33 cout<<"v0:"; 34 output(v0); 35 36 vector<int> v1{v0}; 37 sort(v1.begin(),v1.end()); 38 cout<<"v1:"; 39 output(v1); 40 41 vector<int> v2{v0}; 42 sort(v2.begin()+1,v2.end()-1); 43 cout<<"v2:"; 44 output(v2); 45 } 46 void test2(){ 47 using namespace std; 48 vector<int> v0(10); 49 generate(v0.begin(),v0.end(),generate_random_number); 50 cout<<"v0:"; 51 output(v0); 52 53 auto min_iter=min_element(v0.begin(),v0.end()); 54 auto max_iter=max_element(v0.begin(),v0.end()); 55 cout<<"最小值:"<<*min_iter<<endl; 56 cout<<"最大值:"<<*max_iter<<endl; 57 58 auto ans=minmax_element(v0.begin(),v0.end()); 59 cout<<"最小值:"<<*(ans.first)<<endl; 60 cout<<"最大值:"<<*(ans.second)<<endl; 61 62 double avg1=accumulate(v0.begin(),v0.end(),0.0)/v0.size(); 63 cout<<"均值:"<<fixed<<setprecision(2)<<avg1<<endl; 64 65 sort(v0.begin(),v0.end()); 66 double avg2=accumulate(v0.begin()+1,v0.end()-1,0.0)/(v0.size()-2); 67 cout<<"去掉最大值、最小值之后,均值:"<<avg2<<endl; 68 }
运行结果截图
问题1:generate算法的作用是什么?
答:generate算法通过使用特定的函数生成的结果来对特定区域内的元素进行赋值。
问题2:minmax_element和分别调用min_element、max_element相比,有什么优势?
答:调用一次minmax_element就可以同时找到最大值和最小值,相比于分别调用min_element和max_element,减少了遍历次数,也提高了程序的运行效率。
问题3:把代码中函数generate_random_number的声明和定义注释起来,把两处调用改成如下写法,观察效果是否等同?查阅c++中lambda表达式用法。
答:效果等同,两种方法都可以生成0到100内的随机数。lambda包含捕获列表、参数列表、可变规格、异常说明、返回类型、函数体,这里的[]和()表示不捕获外部变量且没有参数,同时返回类型由编译器自动推导为int型。
三、实验任务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 std::cout<<"测试1:字符串大小写转换\n"; 10 test1(); 11 std::cout<<"\n测试2:字符变换\n"; 12 test2(); 13 } 14 unsigned char func(unsigned char c){ 15 if(c=='z') 16 return 'a'; 17 if(c=='A') 18 return 'A'; 19 if(std::isalpha(c)) 20 return static_cast<unsigned char>(c+1); 21 return c; 22 } 23 void test1(){ 24 std::string s1{"Hello World 2049!"}; 25 std::cout<<"s1="<<s1<<'\n'; 26 std::string s2; 27 for(auto c:s1) 28 s2+=std::tolower(c); 29 std::cout<<"s2="<<s2<<'\n'; 30 std::string s3; 31 for(auto c:s1) 32 s3+=std::toupper(c); 33 std::cout<<"s3="<<s3<<'\n'; 34 } 35 void test2(){ 36 std::string s1{"I love cosmos!"}; 37 std::cout<<"s1="<<s1<<'\n'; 38 std::string s2(s1.size(),' '); 39 std::transform(s1.begin(),s1.end(),s2.begin(),func); 40 std::cout<<"s2="<<s2<<'\n'; 41 }
运行结果截图
问题1:自定义函数func功能是什么?
答:func函数可以把是字母的字符按顺序将其变换为下一个字母(大小写都可以),其中将‘z’变换为‘a’,将‘Z’变换为‘A’。
问题2:tolower和toupper功能分别是什么?
答:tolower可以将大写字母转换为小写,toupper可以将小写字母转换为大写。
问题3:transform的4个参数意义分别是什么?如果把第3个参数s2.begin()改成s1.begin(),有何区别?
答:transform第1和第2个参数规定了将要进行操作的区域,,第3个参数表示放入被转换后字符的起始位置,第4个参数表示要对区域内字符做的操作。如果把第3个参数s2.begin()改成s1.begin(),就会使s1自身被转换,而改前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 while(cin>>s){ 10 cout<<boolalpha 11 <<"区分大小写:"<<is_palindrome(s)<<"\n" 12 <<"不区分大小写:"<<is_palindrome_ignore_case(s)<<"\n\n"; 13 } 14 } 15 bool is_palindrome(const std::string &s){ 16 using namespace std; 17 string s1(s); 18 reverse(s1.begin(),s1.end()); 19 if(s1==s) 20 return true; 21 else 22 return false; 23 } 24 bool is_palindrome_ignore_case(const std::string &s){ 25 using namespace std; 26 string s1; 27 for(auto c:s) 28 s1+=toupper(c); 29 string s2(s1); 30 reverse(s2.begin(),s2.end()); 31 if(s1==s2) 32 return true; 33 else 34 return false; 35 }
运行结果截图
问题:使用cin>>s输入时,输入的字符串中不能包含空格。如果希望测试字符串包含空格,代码应如何调整?
答:使用getline(cin,s)代替cin>>s,可以输入带空格的字符串,但注意需要头文件#include<string>。
五、实验任务5
源代码task5.cpp

1 #include<iostream> 2 #include<string> 3 #include<algorithm> 4 std::string dec2n(int x,int n=2); 5 char func(int x); 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 std::string dec2n(int x,int n){ 18 using namespace std; 19 if(x==0) 20 return "0"; 21 string s; 22 while(x>0){ 23 s+=func(x%n); 24 x/=n; 25 } 26 reverse(s.begin(),s.end()); 27 return s; 28 } 29 char func(int x){ 30 if(x<10) 31 return static_cast<char>('0'+x); 32 else 33 return static_cast<char>('A'+(x-10)); 34 }
运行结果截图
六、实验任务6
源代码task6.cpp

1 #include<iostream> 2 #include<string> 3 #include<vector> 4 #include<algorithm> 5 #include<iomanip> 6 int main(){ 7 using namespace std; 8 cout<<" "<<setw(3); 9 int i=0; 10 while(i<=25){ 11 cout<<static_cast<char>('a'+i)<<setw(3); 12 i++; 13 } 14 cout<<endl; 15 vector<char> v{'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'}; 16 int j=1; 17 while(j<=26) 18 { 19 cout<<j<<setw(3); 20 rotate(v.begin(),v.begin()+1,v.end()); 21 for(auto &i:v) 22 cout<<i<<setw(3); 23 cout<<endl; 24 j++; 25 } 26 }
运行结果截图
七、实验任务7
源代码task7.cpp

1 #include<iostream> 2 #include<vector> 3 #include<iomanip> 4 int number(); 5 char sign(); 6 int func(int x,char a); 7 int calculate(int a,char j,int b); 8 int main(){ 9 using namespace std; 10 srand(std::time(0)); 11 double s; 12 int n=0; 13 int x,y,z; 14 char j; 15 for(int i=1;i<=10;i++){ 16 x=number(); 17 j=sign(); 18 y=func(x,j); 19 cout<<x<<j<<y<<'='; 20 cin>>z; 21 if(z==calculate(x,j,y))n++; 22 cout<<endl; 23 } 24 cout<<"正确率:"<<fixed<<setprecision(2)<<n/10.0*100<<"%"<<endl; 25 } 26 int number(){ 27 return std::rand()%9+1; 28 } 29 char sign(){ 30 using namespace std; 31 vector<char> v0{'+','-','*','/'}; 32 int i=rand()%4; 33 return v0[i]; 34 } 35 int func(int x,char a){ 36 int i; 37 if(a=='+'||a=='*') 38 return std::rand()%9+1; 39 else if(a=='-') 40 return std::rand()%x+1; 41 else{ 42 do{ 43 i=std::rand()%9+1; 44 }while(x%i!=0); 45 return i; 46 } 47 } 48 int calculate(int a,char j,int b){ 49 if(j=='+')return a+b; 50 else if(j=='-')return a-b; 51 else if(j=='*')return a*b; 52 else return a/b; 53 }
运行结果截图
实验总结:
1.如果想要使用using namespace std来简化代码,要先注意好不要出现自命名函数与空间中函数名冲突的情况,防止报错。为了减少错误发生,可以考虑在函数内部使用using namespace std来简化。
2.在使用reverse、rotate等函数时要注意不同函数内的参数,特别是rotate函数中,第二个参数不仅左移1位+1,右移1位-1,而且还要关注左移是从begin开始+1,而右移是从end开始-1。
3.在函数返回类型是bool类型时,直接return true和false,不要加" ",因为true和false就是它的参数。
4.水平制表和setw( )都可以用来控制格式,但'\t'通常只能移动固定的8个字符距离,且不关心上一个内容,对于不同长度数据的对齐不太方便。setw更加灵活,可以随意控制长度,还会默认空格补齐。