实验1 现代C++编程初体验
实验任务1
task1.cpp
1 // 现代C++标准库、算法库体验 2 // 本例用到以下内容: 3 // 1. 字符串string, 动态数组容器类vector、迭代器 4 // 2. 算法库:反转元素次序、旋转元素 5 // 3. 函数模板、const引用作为形参 6 #include <iostream> 7 #include <string> 8 #include <vector> 9 #include <algorithm> 10 11 using namespace std; 12 13 // 辅助函数:输出vector内容 14 template<typename T> 15 void output(const vector<T>& v) { 16 for (const auto& item : v) { 17 cout << item << " "; 18 } 19 cout << endl; 20 } 21 22 // 测试1:组合使用算法库、迭代器、string反转字符串对象 23 void test1() { 24 string s0 = "Hello, C++ Standard Library!"; 25 cout << "s0 = " << s0 << endl; 26 27 string s1(s0); 28 // 反转s1自身 29 reverse(s1.begin(), s1.end()); 30 cout << "s1 = " << s1 << endl; 31 32 string s2(s0.size(), ' '); 33 // 将s0反转后结果拷贝到s2, s0自身不变 34 reverse_copy(s0.begin(), s0.end(), s2.begin()); 35 cout << "s2 = " << s2 << endl; 36 } 37 38 // 测试2:组合使用算法库、迭代器、vector反转动态数组对象vector内数据 39 void test2() { 40 vector<int> v0{ 2, 0, 4, 9 }; 41 cout << "v0: "; output(v0); 42 43 vector<int> v1{ v0 }; 44 reverse(v1.begin(), v1.end()); 45 cout << "v1: "; output(v1); 46 47 vector<int> v2{ v0 }; 48 reverse_copy(v0.begin(), v0.end(), v2.begin()); 49 cout << "v2: "; output(v2); 50 } 51 52 // 测试3:组合使用算法库、迭代器、vector实现元素旋转移位 53 void test3() { 54 vector<int> v0{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 55 cout << "v0: "; output(v0); 56 57 vector<int> v1{ v0 }; 58 // 将[v1.begin(), v1.end())区间内元素循环左移1位 59 rotate(v1.begin(), v1.begin() + 1, v1.end()); 60 cout << "v1: "; output(v1); 61 62 vector<int> v2{ v0 }; 63 // 将[v2.begin(), v2.end())区间内元素循环左移2位 64 rotate(v2.begin(), v2.begin() + 2, v2.end()); 65 cout << "v2: "; output(v2); 66 67 vector<int> v3{ v0 }; 68 // 将[v3.begin(), v3.end())区间内元素循环右移1位 69 rotate(v3.begin(), v3.end() - 1, v3.end()); 70 cout << "v3: "; output(v3); 71 72 vector<int> v4{ v0 }; 73 // 将[v4.begin(), v4.end())区间内元素循环右移2位 74 rotate(v4.begin(), v4.end() - 2, v4.end()); 75 cout << "v4: "; output(v4); 76 } 77 78 int main() { 79 cout << "=== 测试1:字符串反转 ===" << endl; 80 test1(); 81 cout << endl; 82 83 cout << "=== 测试2:vector反转 ===" << endl; 84 test2(); 85 cout << endl; 86 87 cout << "=== 测试3:vector旋转 ===" << endl; 88 test3(); 89 90 return 0; 91 }
reverse(反转):
-
操作方式:直接在原容器上进行反转操作
-
数据影响:会改变原始数据的顺序
-
返回值:没有返回值(void)
-
空间需求:不需要额外空间,在原地完成操作
-
使用场景:当你确实需要反转原容器内容时使用
reverse_copy(反转拷贝):
-
操作方式:将原容器的反转结果拷贝到另一个目标容器中
-
数据影响:不会改变原始数据的顺序,原容器保持不变
-
返回值:返回指向目标容器最后一个元素后面位置的迭代器
-
空间需求:需要预先分配好大小的目标容器
-
使用场景:当你需要保留原数据,同时获得反转副本时使用
三个参数的含义:
-
first:指向要旋转区间开始位置的迭代器
-
middle:指向要成为新序列第一个元素的迭代器(旋转的轴心点)
-
last:指向要旋转区间结束位置的迭代器(最后一个元素的下一个位置)
工作方式:
rotate 算法将 [first, last)
区间内的元素看作一个环形,然后将这个环形旋转,使得原来在 middle 位置的元素移动到 first 位置,其他元素相应地循环移位。
实验任务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 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 return 0; // 添加返回值 25 } 26 27 // 输出容器对象c中的元素 28 template <typename T> 29 void output(const T& c) { 30 for (auto& i : c) 31 std::cout << i << ' '; 32 std::cout << '\n'; 33 } 34 35 // 返回[0, 100]区间内的一个随机整数 36 int generate_random_number() { 37 return std::rand() % 101; 38 } 39 40 // 测试1:对容器类对象指定迭代器区间赋值、排序 41 void test1() { 42 using namespace std; 43 vector<int> v0(10); // 创建一个动态数组对象v0, 对象大小为10 44 generate(v0.begin(), v0.end(), generate_random_number); // 生成随机数填充v0 45 cout << "v0: "; output(v0); 46 vector<int> v1{ v0 }; 47 sort(v1.begin(), v1.end()); // 对整个vector排序 48 cout << "v1: "; output(v1); 49 vector<int> v2{ v0 }; 50 sort(v2.begin() + 1, v2.end() - 1); // 只对中间部分排序,不包含首尾元素 51 cout << "v2: "; output(v2); 52 } 53 54 // 测试2:对容器类对象指定迭代器区间赋值、计算最大值/最小值/均值 55 void test2() { 56 using namespace std; 57 vector<int> v0(10); 58 generate(v0.begin(), v0.end(), generate_random_number); 59 cout << "v0: "; output(v0); 60 // 求最大值和最小值 61 auto min_iter = min_element(v0.begin(), v0.end()); 62 auto max_iter = max_element(v0.begin(), v0.end()); 63 cout << "最小值: " << *min_iter << endl; 64 cout << "最大值: " << *max_iter << endl; 65 // 同时求最大值和最小值 66 auto ans = minmax_element(v0.begin(), v0.end()); 67 cout << "最小值: " << *(ans.first) << endl; 68 cout << "最大值: " << *(ans.second) << endl; 69 // 求平均值 70 double avg1 = accumulate(v0.begin(), v0.end(), 0.0) / v0.size(); 71 cout << "均值: " << fixed << setprecision(2) << avg1 << endl; 72 73 // 创建排序后的副本,避免修改原数据 74 vector<int> v_sorted = v0; 75 sort(v_sorted.begin(), v_sorted.end()); 76 double avg2 = accumulate(v_sorted.begin() + 1, v_sorted.end() - 1, 0.0) / (v_sorted.size() - 2); 77 cout << "去掉最大值、最小值之后,均值: " << fixed << setprecision(2) << avg2 << endl; 78 }
generate算法的主要作用是用指定的生成器函数填充容器的元素。
具体功能:
-
遍历指定区间内的每个元素位置
-
对每个位置调用生成器函数
-
将生成器函数的返回值赋给该位置的元素
-
完成对整个区间的填充
在需要同时查找最小值和最大值的情况下,minmax_element
在性能、代码简洁性和数据一致性方面都具有明显优势。
实验任务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 std::cout << "\n测试2: 字符变换\n"; 14 test2(); 15 return 0; 16 } 17 18 unsigned char func(unsigned char c) { 19 if (c == 'z') 20 return 'a'; 21 22 if (c == 'Z') 23 return 'A'; 24 25 if (std::isalpha(c)) 26 return static_cast<unsigned char>(c + 1); 27 28 return c; 29 } 30 31 void test1() { 32 std::string s1{ "Hello World 2049!" }; 33 std::cout << "s1 = " << s1 << '\n'; 34 std::string s2; 35 for (auto c : s1) 36 s2 += static_cast<char>(std::tolower(c)); 37 std::cout << "s2 = " << s2 << '\n'; 38 std::string s3; 39 for (auto c : s1) 40 s3 += static_cast<char>(std::toupper(c)); 41 std::cout << "s3 = " << s3 << '\n'; 42 } 43 44 void test2() { 45 std::string s1{ "I love cosmos!" }; 46 std::cout << "s1 = " << s1 << '\n'; 47 48 std::string s2(s1.size(), ' '); 49 std::transform(s1.begin(), s1.end(), 50 s2.begin(), 51 func); 52 std::cout << "s2 = " << s2 << '\n'; 53 }
func 函数实现了一个简单的字符变换规则:
-
字母循环移位:
-
小写字母:
'a'→'b'
,'b'→'c'
, ...,'z'→'a'
-
大写字母:
'A'→'B'
,'B'→'C'
, ...,'Z'→'A'
-
-
特殊处理边界情况:
-
'z'
转换为'a'
-
'Z'
转换为'A'
-
-
非字母字符保持不变
tolower:
-
功能:将字符转换为小写形式
-
参数:接受一个字符(实际是int类型)
-
返回值:对应的小写字符(int类型,需要转换)
toupper:
-
功能:将字符转换为大写形式
-
参数:接受一个字符(实际是int类型)
-
返回值:对应的大写字符(int类型,需要转换)
-
第一个参数:
s1.begin()
- 输入序列的起始位置 -
第二个参数:
s1.end()
- 输入序列的结束位置(不包含) -
第三个参数:
s2.begin()
- 输出序列的起始位置 -
第四个参数:
func
- 应用于每个元素的变换函数
关键区别:
-
安全性:使用
s2.begin()
更安全,保留原始数据 -
内存效率:使用
s1.begin()
更节省内存
实验任务4
task3.cpp
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 // 多组输入,直到按下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 return std::equal(s.begin(), s.begin() + s.size() / 2, s.rbegin()); 23 } 24 25 // 函数is_palindrome_ignore_case定义 - 不区分大小写的回文检测 26 bool is_palindrome_ignore_case(const std::string& s) { 27 std::string lower_s; 28 // 转换为小写 29 std::transform(s.begin(), s.end(), std::back_inserter(lower_s), 30 [](unsigned char c) { return std::tolower(c); }); 31 // 检测回文 32 return std::equal(lower_s.begin(), lower_s.begin() + lower_s.size() / 2, 33 lower_s.rbegin()); 34 }
主要调整:
-
使用
getline(cin, s)
替代cin >> s
-
添加
cin.ignore()
清除输入缓冲区 -
添加空字符串检查 避免处理空输入
-
在输出中显示测试字符串 方便查看包含空格的输入
实验任务5
task5.cpp
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定义 - 将十进制数x转换为n进制字符串 20 std::string dec2n(int x, int n) { 21 // 处理特殊情况:0 22 if (x == 0) return "0"; 23 24 // 检查进制范围是否合法 25 if (n < 2 || n > 36) { 26 return "Invalid base"; 27 } 28 29 std::string result; 30 bool is_negative = false; 31 32 // 处理负数 33 if (x < 0) { 34 is_negative = true; 35 x = -x; // 转换为正数处理 36 } 37 38 // 数字字符集,支持最高36进制 39 const char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 40 41 // 通过除n取余法进行进制转换 42 while (x > 0) { 43 int remainder = x % n; 44 result += digits[remainder]; // 将余数转换为对应字符 45 x /= n; 46 } 47 48 // 反转字符串,因为我们是逆序添加的 49 std::reverse(result.begin(), result.end()); 50 51 // 如果是负数,添加负号 52 if (is_negative) { 53 result = "-" + result; 54 } 55 56 return result; 57 }
实验任务6
1 #include <iostream> 2 #include <string> 3 #include <iomanip> 4 5 void generate_caesar_cipher_table() { 6 std::string alphabet = "abcdefghijklmnopqrstuvwxyz"; 7 8 std::cout << "凯撒密码完整对照表\n"; 9 std::cout << "==================\n\n"; 10 11 // 打印表头 12 std::cout << std::setw(2) << "" << " "; 13 for (char c : alphabet) { 14 std::cout << c; 15 } 16 std::cout << "\n"; 17 18 // 生成每个移位量的密码表 19 for (int shift = 1; shift <= 26; shift++) { 20 std::cout << std::setw(2) << shift; 21 22 std::string cipher_text; 23 for (char c : alphabet) { 24 // 凯撒密码移位计算 25 char encrypted; 26 if (c >= 'a' && c <= 'z') { 27 encrypted = 'a' + (c - 'a' + shift) % 26; 28 } 29 else { 30 encrypted = c; // 保持非字母字符不变 31 } 32 cipher_text += encrypted; 33 } 34 35 std::cout << cipher_text << "\n"; 36 } 37 } 38 39 void generate_caesar_cipher_table_uppercase() { 40 std::string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 41 42 std::cout << "\n凯撒密码完整对照表 (大写字母)\n"; 43 std::cout << "==========================\n\n"; 44 45 // 打印表头 46 std::cout << std::setw(2) << "" << " "; 47 for (char c : alphabet) { 48 std::cout << c; 49 } 50 std::cout << "\n"; 51 52 // 生成每个移位量的密码表 53 for (int shift = 1; shift <= 26; shift++) { 54 std::cout << std::setw(2) << shift; 55 56 std::string cipher_text; 57 for (char c : alphabet) { 58 // 凯撒密码移位计算 59 char encrypted; 60 if (c >= 'A' && c <= 'Z') { 61 encrypted = 'A' + (c - 'A' + shift) % 26; 62 } 63 else { 64 encrypted = c; // 保持非字母字符不变 65 } 66 cipher_text += encrypted; 67 } 68 69 std::cout << cipher_text << "\n"; 70 } 71 } 72 73 // 交互式加密功能 74 void interactive_caesar_cipher() { 75 std::cout << "\n=== 交互式凯撒密码加密 ===\n"; 76 77 std::string text; 78 int shift; 79 80 std::cout << "请输入要加密的文本: "; 81 std::cin.ignore(); // 清除输入缓冲区 82 std::getline(std::cin, text); 83 84 std::cout << "请输入移位量 (1-25): "; 85 std::cin >> shift; 86 87 if (shift < 1 || shift > 25) { 88 std::cout << "移位量必须在 1-25 之间!\n"; 89 return; 90 } 91 92 std::string encrypted_text; 93 for (char c : text) { 94 if (c >= 'a' && c <= 'z') { 95 // 小写字母 96 encrypted_text += 'a' + (c - 'a' + shift) % 26; 97 } 98 else if (c >= 'A' && c <= 'Z') { 99 // 大写字母 100 encrypted_text += 'A' + (c - 'A' + shift) % 26; 101 } 102 else { 103 // 非字母字符保持不变 104 encrypted_text += c; 105 } 106 } 107 108 std::cout << "加密结果: " << encrypted_text << "\n"; 109 110 // 解密演示 111 std::string decrypted_text; 112 for (char c : encrypted_text) { 113 if (c >= 'a' && c <= 'z') { 114 decrypted_text += 'a' + (c - 'a' - shift + 26) % 26; 115 } 116 else if (c >= 'A' && c <= 'Z') { 117 decrypted_text += 'A' + (c - 'A' - shift + 26) % 26; 118 } 119 else { 120 decrypted_text += c; 121 } 122 } 123 124 std::cout << "解密结果: " << decrypted_text << "\n"; 125 } 126 127 int main() { 128 int choice; 129 130 do { 131 std::cout << "\n凯撒密码系统\n"; 132 std::cout << "=============\n"; 133 std::cout << "1. 显示小写字母凯撒密码表\n"; 134 std::cout << "2. 显示大写字母凯撒密码表\n"; 135 std::cout << "3. 交互式加密解密\n"; 136 std::cout << "4. 退出\n"; 137 std::cout << "请选择功能 (1-4): "; 138 std::cin >> choice; 139 140 switch (choice) { 141 case 1: 142 generate_caesar_cipher_table(); 143 break; 144 case 2: 145 generate_caesar_cipher_table_uppercase(); 146 break; 147 case 3: 148 interactive_caesar_cipher(); 149 break; 150 case 4: 151 std::cout << "程序结束,再见!\n"; 152 break; 153 default: 154 std::cout << "无效选择,请重新输入!\n"; 155 } 156 } while (choice != 4); 157 158 return 0; 159 }
实验任务7
1 #include <iostream> 2 #include <cstdlib> 3 #include <ctime> 4 #include <iomanip> 5 #include <string> 6 7 using namespace std; 8 9 // 生成随机数 [min, max] 10 int generate_random_number(int min, int max) { 11 return rand() % (max - min + 1) + min; 12 } 13 14 // 生成加法题目 15 void generate_addition(int& num1, int& num2, string& question) { 16 num1 = generate_random_number(1, 10); 17 num2 = generate_random_number(1, 10); 18 question = to_string(num1) + " + " + to_string(num2) + " = "; 19 } 20 21 // 生成减法题目 22 void generate_subtraction(int& num1, int& num2, string& question) { 23 num1 = generate_random_number(1, 10); 24 num2 = generate_random_number(1, num1); // 确保num1 >= num2 25 question = to_string(num1) + " - " + to_string(num2) + " = "; 26 } 27 28 // 生成乘法题目 29 void generate_multiplication(int& num1, int& num2, string& question) { 30 num1 = generate_random_number(1, 10); 31 num2 = generate_random_number(1, 10); 32 question = to_string(num1) + " × " + to_string(num2) + " = "; 33 } 34 35 // 生成除法题目 36 void generate_division(int& num1, int& num2, string& question) { 37 num2 = generate_random_number(1, 10); 38 int result = generate_random_number(1, 10); 39 num1 = num2 * result; // 确保能整除 40 question = to_string(num1) + " ÷ " + to_string(num2) + " = "; 41 } 42 43 int main() { 44 // 设置随机种子 45 srand(time(0)); 46 47 int correct_count = 0; 48 const int total_questions = 10; 49 50 cout << "小学生算术运算测试" << endl; 51 cout << "==================" << endl; 52 53 for (int i = 1; i <= total_questions; i++) { 54 int num1, num2, correct_answer, user_answer; 55 string question; 56 57 // 随机选择运算类型 (0:加法, 1:减法, 2:乘法, 3:除法) 58 int operation_type = rand() % 4; 59 60 switch (operation_type) { 61 case 0: // 加法 62 generate_addition(num1, num2, question); 63 correct_answer = num1 + num2; 64 break; 65 case 1: // 减法 66 generate_subtraction(num1, num2, question); 67 correct_answer = num1 - num2; 68 break; 69 case 2: // 乘法 70 generate_multiplication(num1, num2, question); 71 correct_answer = num1 * num2; 72 break; 73 case 3: // 除法 74 generate_division(num1, num2, question); 75 correct_answer = num1 / num2; 76 break; 77 } 78 79 // 显示题目并获取用户答案 80 cout << "第" << i << "题: " << question; 81 cin >> user_answer; 82 83 // 检查答案 84 if (user_answer == correct_answer) { 85 cout << "正确!" << endl; 86 correct_count++; 87 } 88 else { 89 cout << "错误!正确答案是: " << correct_answer << endl; 90 } 91 cout << endl; 92 } 93 94 // 计算并显示正确率 95 double accuracy = (static_cast<double>(correct_count) / total_questions) * 100; 96 cout << "测试结束!" << endl; 97 cout << "你答对了 " << correct_count << " 道题,共 " << total_questions << " 道题" << endl; 98 cout << fixed << setprecision(2); 99 cout << "正确率: " << accuracy << "%" << endl; 100 101 return 0; 102 }