实验1
实验任务1:
源代码:
1 #include <iostream> 2 #include <string> 3 #include <vector> 4 #include <algorithm> 5 6 template<typename T> 7 void output(const T &c); 8 void test1(); 9 void test2(); 10 void test3(); 11 int main() { 12 std::cout << "测试1: \n"; 13 test1(); 14 std::cout << "\n测试2: \n"; 15 test2(); 16 std::cout << "\n测试3: \n"; 17 test3(); 18 } 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 27 void test1() { 28 using namespace std; 29 string s0{"0123456789"}; 30 cout << "s0 = " << s0 << endl; 31 string s1(s0); 32 reverse(s1.begin(), s1.end()); 33 cout << "s1 = " << s1 << endl; 34 string s2(s0.size(), ' '); 35 reverse_copy(s0.begin(), s0.end(), s2.begin()); 36 cout << "s2 = " << s2 << endl; 37 } 38 39 void test2() { 40 using namespace std; 41 vector<int> v0{2, 0, 4, 9}; 42 cout << "v0: "; output(v0); 43 vector<int> v1{v0}; 44 reverse(v1.begin(), v1.end()); 45 cout << "v1: "; output(v1); 46 vector<int> v2{v0}; 47 reverse_copy(v0.begin(), v0.end(), v2.begin()); 48 cout << "v2: "; output(v2); 49 } 50 51 void test3() { 52 using namespace std; 53 vector<int> v0{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; 54 cout << "v0: "; output(v0); 55 vector<int> v1{v0}; 56 rotate(v1.begin(), v1.begin()+1, v1.end()); 57 cout << "v1: "; output(v1); 58 vector<int> v2{v0}; 59 rotate(v2.begin(), v2.begin()+2, v2.end()); 60 cout << "v2: "; output(v2); 61 vector<int> v3{v0}; 62 rotate(v3.begin(), v3.end()-1, v3.end()); 63 cout << "v3: "; output(v3); 64 vector<int> v4{v0}; 65 rotate(v4.begin(), v4.end()-2, v4.end()); 66 cout << "v4: "; output(v4); 67 }
运行结果:
问题1:reverse 和 reverse_copy 有什么区别?
答: reverse是将字符串原地反转,会修改原容器内容;
reverse_copy是将字符串反转后复制到另外一个容器中,不会对原容器产生改变。
问题2:rotate 算法是如何改变元素顺序的?它的三个参数分别代表什么?
答: rotate是将元素进行循环旋转,将第一个参数和第二个参数之间的数据(包含第一个参数所代表的数据)依次移到第三个参数所代表的数据后面。
第一个参数:旋转范围的起始位置
第二个参数:旋转后的第一个元素的位置
第三个参数:旋转范围的末尾元素的后一个位置
实验任务2:
源代码:
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 12 int generate_random_number(); 13 void test1(); 14 void test2(); 15 16 int main() { 17 std::srand(std::time(0)); 18 std::cout << "测试1: \n"; 19 test1(); 20 std::cout << "\n测试2: \n"; 21 test2(); 22 } 23 24 template <typename T> 25 26 void output(const T &c) { 27 for(auto &i: c) 28 std::cout << i << ' '; 29 std::cout << '\n'; 30 } 31 32 int generate_random_number() { 33 return std::rand() % 101; 34 } 35 36 void test1() { 37 using namespace std; 38 vector<int> v0(10); 39 generate(v0.begin(), v0.end(), generate_random_number); 40 cout << "v0: "; output(v0); 41 vector<int> v1{v0}; 42 sort(v1.begin(), v1.end()); 43 cout << "v1: "; output(v1); 44 vector<int> v2{v0}; 45 sort(v2.begin()+1, v2.end()-1); 46 cout << "v2: "; output(v2); 47 } 48 49 void test2() { 50 using namespace std; 51 vector<int> v0(10); 52 generate(v0.begin(), v0.end(), generate_random_number); 53 cout << "v0: "; output(v0); 54 55 auto min_iter = min_element(v0.begin(), v0.end()); 56 auto max_iter = max_element(v0.begin(), v0.end()); 57 cout << "最小值: " << *min_iter << endl; 58 cout << "最大值: " << *max_iter << endl; 59 60 auto ans = minmax_element(v0.begin(), v0.end()); 61 cout << "最小值: " << *(ans.first) << endl; 62 cout << "最大值: " << *(ans.second) << endl; 63 64 double avg1 = accumulate(v0.begin(), v0.end(), 0.0) / v0.size(); 65 cout << "均值: " << fixed << setprecision(2) << avg1 << endl; 66 67 sort(v0.begin(), v0.end()); 68 double avg2 = accumulate(v0.begin()+1, v0.end()-1, 0.0) / (v0.size()-2); 69 cout << "去掉最大值、最小值之后,均值: " << avg2 << endl; 70 }
运行结果:
问题1:generate 算法的作用是什么?
答: 将generate_random_number生成的随机数依次赋值给容器中每一个元素。
问题2:minmax_element 和分别调用 min_element 、 max_element 相比,有什么优势?
答: minmax_element 只需要遍历一次就能找到最大最小值,而min_element 、 max_element 共需要遍历两次; minmax_element能减少遍历的开销,且代码行数减少,更简洁
问题3:把代码中函数 generate_random_number 的声明(line12)和定义(line32-34)注释起来,把两处调用改成如下写法,观察效果是否等同?查阅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适用于代码简洁的函数中,可以简化代码,无需重复,[](){}中[]用于捕获外部变量,()包含参数列表,{}包含函数体,有具体逻辑。
实验任务3:
源代码:
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 9 int main() { 10 std::cout << "测试1: 字符串大小写转换\n"; 11 test1(); 12 std::cout << "\n测试2: 字符变换\n"; 13 test2(); 14 } 15 16 unsigned char func(unsigned char c) { 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 26 void test1() { 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 39 void test2() { 40 std::string s1{"I love cosmos!"}; 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 }
运行结果:
问题1:自定义函数 func 功能是什么?
答: func 用于对单个字符的转换,即向下一个字母移动,如果到边界,则循环至第一个字母。
问题2:tolower 和 toupper 功能分别是什么?
答: tolower是将大写字母转换为对应的小写字母,原来小写字母保持不变;
toupper是将小写字母转换为对应的大写字母,原来大写字母保持不变。
问题3:transform 的4个参数意义分别是什么?如果把第3个参数 s2.begin() 改成 s1.begin() ,有何区别?
答: s1.begin()为输入元素的起点,s1.end()为输入元素的终点,s2.begin()为转换后元素的起点位置,func为操作函数;
s2.begin()是将转换后元素保存到新容器中,对于原容器元素不会改变,而 s1.begin()是在原容器中进行修改,会覆盖原容器元素。
实验任务4:
源代码:
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 // 多组输入,直到按下Ctrl+Z结束测试 10 while(cin >> s) { 11 cout << boolalpha<< "区分大小写: " << is_palindrome(s) << "\n" 12 << "不区分大小写: " << is_palindrome_ignore_case(s) << "\n\n"; 13 } 14 } 15 bool is_palindrome(const std::string &s){ 16 for(int i=0;i<s.size()/2;i++){ 17 if(s[i]!=s[s.size()-i-1]) 18 return false; 19 } 20 return true; 21 } 22 bool is_palindrome_ignore_case(const std::string &s){ 23 std::string s1; 24 for(auto c: s) 25 s1 += std::toupper(c); 26 return is_palindrome(s1); 27 }
运行结果:
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 if (x == 0) { 18 return "0"; 19 } 20 std::string s; 21 while(x>0){ 22 if(x%n<10){ 23 s+='0'+x%n; 24 } 25 else 26 s+='A'+x%n-10; 27 x/=n; 28 } 29 std::reverse(s.begin(),s.end()); 30 return s; 31 }
运行结果:
实验任务6:
源代码:
1 #include <iostream> 2 #include <string> 3 #include <iomanip> 4 #include <algorithm> 5 using namespace std; 6 7 int main() { 8 std::string s; 9 std::string s1; 10 for (char c = 'a'; c <= 'z'; c++) { 11 s+=c; 12 } 13 std::cout<<right<<std::setw(2)<<" "; 14 for(auto c: s){ 15 std::cout << std::right << std::setw(2) <<c; 16 s1 += std::toupper(c); 17 } 18 cout<<endl; 19 for(int i=1;i<=26;i++){ 20 std::cout << std::right << std::setw(2) << i; 21 std::rotate(s1.begin(),s1.begin() + 1,s1.end()); 22 for(auto c: s1){ 23 std::cout << std::right << std::setw(2) <<c; 24 } 25 cout<<endl; 26 } 27 return 0; 28 }
运行结果:
实验任务7:
源代码:
1 #include <iostream> 2 #include <cstdlib> 3 #include <ctime> 4 #include <iomanip> 5 using namespace std; 6 7 char getsign(int sign){ 8 switch(sign){ 9 case 0:return'+'; 10 case 1:return'-'; 11 case 2:return'*'; 12 case 3:return'/'; 13 default: return 0; 14 } 15 } 16 17 int calculate(int sign,int num1,int num2){ 18 switch(sign){ 19 case 0:return num1+num2; 20 case 1:return num1-num2; 21 case 2:return num1*num2; 22 case 3:return num1/num2; 23 default: return 0; 24 } 25 } 26 27 int main() { 28 srand(time(0)); 29 int num1,num2; 30 int count=0; 31 int ans; 32 for(int i=0;i<10;i++){ 33 int sign=rand()%4; 34 bool get = false; 35 while(!get){ 36 num1=rand()%10+1; 37 num2=rand()%10+1; 38 if(sign==1&&num1<num2){ 39 get=false; 40 } 41 else if(sign==3&&num1%num2!=0) 42 get=false; 43 else 44 get=true; 45 } 46 cout<<num1<<getsign(sign)<<num2<<'=' ; 47 cin>>ans; 48 cout<<endl; 49 if(ans==calculate(sign,num1,num2)){ 50 count++; 51 } 52 } 53 cout<<"正确率:" <<fixed<<setprecision(2)<<count/10.00*100<<"%" <<endl; 54 }
运行结果:
总结:通过这次实验,我对c++自带标准库组件了解了更多,同时也逐渐学会应用它解决问题,同时自身代码能力也有了一定的提升。