实验1 现代C++编程初体验

实验1 现代C++编程初体验

实验一

源代码:

 1 #include <iostream>
 2 #include <string>
 3 #include <vector>
 4 #include <algorithm>
 5 
 6 template<typename T>
 7 void output(const T& c);
 8 
 9 void test1();
10 void test2();
11 void test3();
12 
13 int main() {
14     std::cout << "测试1: \n";
15     test1();
16 
17     std::cout << "\n测试2: \n";
18     test2();
19 
20     std::cout << "\n测试3: \n";
21     test3();
22 }
23 
24 template <typename T>
25 void output(const T& c) {
26     for (auto& i : c)
27         std::cout << i << ' ';
28     std::cout << '\n';
29 }
30 
31 void test1() {
32     using namespace std;
33 
34     string s0{ "0123456789" };
35     cout << "s0 = " << s0 << endl;
36 
37     string s1(s0);
38     reverse(s1.begin(), s1.end());
39     cout << "s1 = " << s1 << endl;
40 
41     string s2(s0.size(), ' ');
42     reverse_copy(s0.begin(), s0.end(), s2.begin());
43     cout << "s2 = " << s2 << endl;
44 }
45 
46 void test2() {
47     using namespace std;
48 
49     vector<int> v0{ 2, 0, 4, 9 };
50     cout << "v0: "; output(v0);
51 
52     vector<int> v1(v0);
53     reverse(v1.begin(), v1.end());
54     cout << "v1: "; output(v1);
55 
56     vector<int> v2(v0);
57     reverse_copy(v0.begin(), v0.end(), v2.begin());
58     cout << "v2: "; output(v2);
59 }
60 
61 void test3() {
62     using namespace std;
63 
64     vector<int> v0{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
65     cout << "v0: "; output(v0);
66 
67     vector<int> v1(v0);
68     rotate(v1.begin(), v1.begin() + 1, v1.end());
69     cout << "v1: "; output(v1);
70 
71     vector<int> v2(v0);
72     rotate(v2.begin(), v2.begin() + 2, v2.end());
73     cout << "v2: "; output(v2);
74 
75     vector<int> v3(v0);
76     rotate(v3.begin(), v3.end() - 1, v3.end());
77     cout << "v3: "; output(v3);
78 
79     vector<int> v4(v0);
80     rotate(v4.begin(), v4.end() - 2, v4.end());
81     cout << "v4: "; output(v4);
82 }

运行测试截图:

image

回答问题:

问题1:reverse 和 reverse_copy 有什么区别?

     答:reverse直接反转了输入的字符串元素,修改了原容器本身;

            reverse_copy将输入的字符串元素反转后复制到目标容器,不修改原容器内容。

问题2: rotate 算法是如何改变元素顺序的?它的三个参数分别代表什么?

     答:rotate算法调整了元素顺序:把从第一个参数位置开始,到第二个参数位置之前的所有元素,整体移到第三个参数位置的后面。

            第一个参数:要移位的元素范围的起始处

            第二个参数:移位后,放在最前面的元素的原来位置

            第三个参数:要移位的元素范围的结束处,即最后一个元素的下一位

实验二

源代码:

 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 
21     std::cout << "\n测试2: \n";
22     test2();
23 }
24 
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 
32 int generate_random_number() {
33     return std::rand() % 101;
34 }
35 
36 void test1() {
37     using namespace std;
38 
39     vector<int> v0(10);
40     generate(v0.begin(), v0.end(), generate_random_number);
41     cout << "v0: "; output(v0);
42 
43     vector<int> v1{v0};
44     sort(v1.begin(), v1.end());
45     cout << "v1: "; output(v1);
46 
47     vector<int> v2{v0};
48     sort(v2.begin()+1, v2.end()-1);
49     cout << "v2: "; output(v2);
50 }
51 
52 void test2() {
53     using namespace std;
54 
55     vector<int> v0(10);
56     generate(v0.begin(), v0.end(), generate_random_number);
57     cout << "v0: "; 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 
64     auto ans = minmax_element(v0.begin(), v0.end());
65     cout << "最小值: " << *(ans.first) << endl;
66     cout << "最大值: " << *(ans.second) << endl;
67 
68     double avg1 = accumulate(v0.begin(), v0.end(), 0.0) / v0.size();
69     cout << "均值: " << fixed << setprecision(2) << avg1 << endl;
70 
71     sort(v0.begin(), v0.end());
72     double avg2 = accumulate(v0.begin()+1, v0.end()-1, 0.0) / (v0.size()-2);
73     cout << "去掉最大值、最小值之后,均值: " << avg2 << endl;
74 }

运行测试截图:

image

 回答问题:

 问题1: generate 算法的作用是什么?
     答:用指定函数生成的值依次填充容器中指定范围的元素,本代码中指定范围为数组头尾位置,指定函数为一个可以生成随机数的函数。
问题2: minmax_element 和分别调用 min_element 、 max_element 相比,有什么优势?
     答:minmax_element 只需遍历一次容器,就能就能同时找到最小值和最大值的迭代器,而分别调用 min_element 、 max_element 需要需要遍历容器两次,当元素数量很多的情况下,使用minmax_element降低了算法的时间复杂度。
问题3:查询 generate 第3个参数 [](){return std::rand()%101;} 用法,与使用自定义函数generate_random_number 相比,lambda表达式适用场景是什么?
1 generate(v0.begin(), v0.end(), [](){return std::rand()%101;});

     答:用法:这是一个无参数的 lambda 表达式,功能与自定义函数 generate_random_number 完全相同,都是生成一个 0-100 范围的随机数;

            使用场景:当代码逻辑简单、且只当前位置使用一次 时,用 lambda 表达式更简洁,无需单独定义函数,减少代码编写者负担。

实验三

源代码:

 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     std::cout << "测试1:字符串大小写转换\n";
13     test1();
14 
15     std::cout << "\n测试2:字符变换\n";
16     test2();
17 }
18 
19 unsigned char func(unsigned char c) {
20     if (c == 'z')
21         return 'a';
22 
23     if (c == 'Z')
24         return 'A';
25 
26     if (std::isalpha(c))
27         return static_cast<unsigned char>(c + 1);
28 
29     return c;
30 }
31 
32 void test1() {
33     std::string s1{"Hello world 2049!"};
34     std::cout << "s1 = " << s1 << '\n';
35 
36     std::string s2;
37     for (auto c : s1)
38         s2 += std::tolower(c);
39     std::cout << "s2 = " << s2 << '\n';
40 
41     std::string s3;
42     for (auto c : s1)
43         s3 += std::toupper(c);
44     std::cout << "s3 = " << s3 << '\n';
45 }
46 
47 void test2() {
48     std::string s1{"I love cosmos!"};
49     std::cout << "s1 = " << s1 << '\n';
50 
51     std::string s2(s1.size(), ' ');
52     std::transform(s1.begin(), s1.end(),
53                    s2.begin(),
54                    func);
55     std::cout << "s2 = " << s2 << '\n';
56 }

测试运行截图:

image

回答问题:

问题1:自定义函数 func 功能是什么?
    答:若字符为z/Z,返回a/A;若字符为其他字母,返回其同大小写的后一个字母;不是字母则保持原字符不变。
问题2: tolower 和 toupper 功能分别是什么?
    答:tolower将大写字母转为小写字母;toupper将小写字母转为大写字母;非字母保持不变
问题3: transform 的4个参数意义分别是什么?如果把第3个参数 s2.begin() 改成 s1.begin() ,有何区别?
    答:待处理字符起始位置,待处理字符结束位置(不包含),处理后的字符存放的起始位置,处理字符的方法;原代码中 s2.begin() 表示将操作结果存到新字符串 s2 中,s1 保持不变;若改为 s1.begin(),则操作结果会直接覆盖原字符串 s1 中的内容,导致 s1 的原始数据丢失。

实验四

源代码:

 1 #include <iostream>
 2 #include <string>
 3 #include <algorithm>
 4 #include <cctype>
 5 
 6 bool is_palindrome(const std::string& s);
 7 bool is_palindrome_ignore_case(const std::string& s);
 8 
 9 int main() {
10     using namespace std;
11     string s;
12 
13     // 多组输入,直到按下Ctrl+Z结束测试
14     while (cin >> s) {
15         cout << "区分大小写:" << boolalpha << is_palindrome(s) << "\n";
16         cout << "不区分大小写:" << is_palindrome_ignore_case(s) << "\n\n";
17     }
18 }
19 // 函数is_palindrome定义
20 bool is_palindrome(const std::string& s) {
21     int left = 0, right = s.size() - 1;
22     while (left < right) {
23         if (s[left] != s[right]) {
24             return false;
25         }
26         left++;
27         right--;
28     }
29     return true;
30 }
31 // 函数is_palindrome_ignore_case定义
32 bool is_palindrome_ignore_case(const std::string& s) {
33     std::string temp = s;
34     std::transform(temp.begin(), temp.end(), temp.begin(), ::tolower);
35     int left = 0, right = temp.size() - 1;
36     while (left < right) {
37         if (temp[left] != temp[right]) {
38             return false;
39         }
40         left++;
41         right--;
42     }
43     return true;
44 }

运行测试截图:

image

回答问题:

(1)使用 cin >> s 输入时,输入的字符串中不能包含空格。如果希望测试字符串包含空格(如 hellooop ),代码应如何调整?
           答:可以把 cin >> s 换成 getline(cin, s),因为 cin >> s 会以空格为分隔符停止读取字段,而 getline 可读取包括空格在内的一整行内容。

实验五

源代码:

 1 #include <iostream>
 2 #include <string>
 3 #include <algorithm>
 4 
 5 std::string dec2n(int x, int n = 2);
 6 
 7 int main() {
 8     int x;
 9     while (std::cin >> x) {
10         std::cout << "十进制: " << x << '\n'
11             << "二进制: " << dec2n(x) << '\n'
12             << "八进制: " << dec2n(x, 8) << '\n'
13             << "十二进制: " << dec2n(x, 12) << '\n'
14             << "十六进制: " << dec2n(x, 16) << '\n'
15             << "三十二进制: " << dec2n(x, 32) << "\n\n";
16     }
17 }
18 
19 // 函数dec2n定义
20 std::string dec2n(int x, int n) {
21     if (x == 0) {
22         return "0";
23     }
24 
25     std::string result;
26     while (x > 0) {
27         int remainder = x % n;
28         char digit;
29 
30         if (remainder < 10) {
31             digit = '0' + remainder;
32         }
33         else {
34             digit = 'A' + remainder - 10;
35         }
36 
37         result.push_back(digit);
38         x /= n;
39     }
40 
41     std::reverse(result.begin(), result.end());
42     return result;
43 }

测试运行截图:

image

 实验六

源代码:

 1 #include <iostream>
 2 #include <string>
 3 using namespace std;
 4 
 5 int main() {
 6     cout << "  ";
 7     for (int i = 0; i < 26; i++) {
 8         cout << char('a' + i);
 9         if (i < 25) cout << " ";  
10     }
11     cout << endl;
12 
13     string str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
14     for (int i = 1; i <= 26; i++) {
15         cout << i;  
16 
17         for (int j = 0; j < 26; j++) {
18             int index = (j + i) % 26;  
19             cout << " " << str[index];  
20         }
21         cout << endl;
22     }
23 
24     return 0;
25 }

测试运行截图:

image

实验七:

源代码:

 1 #include <iostream>
 2 #include <cstdlib>
 3 #include <ctime>
 4 #include <iomanip>
 5 using namespace std;
 6 
 7 int main() {
 8     srand(static_cast<unsigned int>(time(0)));
 9 
10     int correctCount = 0;
11     const int questions = 10;
12 
13     for (int i = 0; i < questions; ++i) {
14         int num1 = rand() % 10 + 1;
15         int num2 = rand() % 10 + 1;
16         int op = rand() % 4;
17 
18         int answer, canswer;
19         char opChar;
20 
21         switch (op) {
22         case 0: 
23             opChar = '+';
24             canswer = num1 + num2;
25             break;
26         case 1: 
27             if (num1 < num2) {
28                 swap(num1, num2);
29             }
30             opChar = '-';
31             canswer = num1 - num2;
32             break;
33         case 2: 
34             opChar = '*';
35             canswer = num1 * num2;
36             break;
37         case 3: 
38             while (num2 == 0 || num1 % num2 != 0) {
39                 num1 = rand() % 10 + 1;
40                 num2 = rand() % 10 + 1;
41             }
42             opChar = '/';
43 
44             canswer = num1 / num2;
45             break;
46         }
47 
48         cout << num1 << " " << opChar << " " << num2 << " = ";
49         cin >> answer;
50 
51         if (answer == canswer) {
52             correctCount++;
53         }
54     }
55 
56     double accuracy = static_cast<double>(correctCount) / questions * 100;
57     cout << "正确率:" << fixed << setprecision(2) << accuracy << "%" << endl;
58 
59     return 0;
60 }

测试运行截图:

image

实验总结:

 (1)c++中有许多已经封装好的可以直接使用的函数,使得程序代码变得简洁,但是增加了程序员的记忆负担,需要在一次次的使用中加深印象并且学会使用(此事在前后端开发中亦有记载,什么功能都有,但是要用的时候记不起来)

(2)C++标准库的使用中容器与算法的分离设计有效的提升了代码灵活性,比如同样的sort算法,既能排序vector字段,也能排序string字段,泛用性强。

(3)这些实验灵活组合使用现代C++基础语言特性和标准库,使我慢慢开始从c语言到c++语法的转变并且能够用c++解决基础的编程问题。

 
 

 

 

 

 

 
 

 

           

   

 

posted @ 2025-10-16 22:13  景思翰  阅读(8)  评论(1)    收藏  举报