文章目录
- 💯前言
- 💯题目描述
- 输入格式:
- 输出格式:
- 💯我的做法
- 代码实现:
- 💯老师的做法
- 代码实现:
- 💯对比分析
- 💯拓展与优化
- 💯总结
- 一开始的错误做法
💯前言
- 在编程学习过程中,C++ 语言为我们提供了强大的控制能力和灵活的操作方式。在本次学习中,我们面对的是一个简单的算术口算题目的处理任务。任务要求通过程序自动处理多个口算算式,输出完整的算式、其计算结果,并计算算式的总长度。这个问题看似简单,但可以通过多种方式解决,过程中涉及到字符串拼接、运算符判断和数据存储等基础编程技术。
在本次讨论中,我们将深入分析两种不同的解决方法:我提出的做法与老师的做法。我们将详细对比这两种方法的思路、代码实现,并进行优化和拓展,以便对 C++ 编程的理解更为深刻。
C++ 参考手册
💯题目描述
P1957 口算练习题
题目要求我们处理一组口算题目,每道题目可能包括加法、减法或乘法操作。每道题的输入由两个或三个数据组成,若有三个数据,第一个表示运算符(a
表示加法,b
表示减法,c
表示乘法),接下来的两个数据为参与运算的数值;若只有两个数据,则表示继承上一道题的运算符。
我们需要输出每道题的完整算式,并且输出算式的总长度。以下是题目的完整描述:
输入格式:
4
a 64 46
275 125
c 11 99
b 46 64
输出格式:
64+46=110
9
275+125=400
11
11*99=1089
10
46-64=-18
9
💯我的做法
我的实现方法着眼于输入的处理与字符串的拼接,基本流程如下:
- 输入读取:首先读取题目数量
i
,然后循环处理每一道算式。每道算式可以是完整的带有运算符的输入,也可以是继承上题的运算符。 - 算式计算:对于每道算式,根据运算符
a
,b
, 或c
来决定进行加法、减法或乘法操作。 - 字符串拼接:利用字符串的拼接(
+=
)来构造完整的算式表达式,并计算结果。 - 输出:输出每道算式及其结果,最后输出算式的总长度。
代码实现:
#include <iostream>
#include <string>
using namespace std;int main()
{int i;cin >> i;int a, b;string temp, ysf;while(i--){string s;cin >> temp;if(temp == "a" || temp == "b" || temp == "c"){cin >> a >> b;if(temp == "a"){s += to_string(a);s += '+';s += to_string(b);s += '=';s += to_string(a + b);}else if(temp == "b"){s += to_string(a);s += '-';s += to_string(b);s += '=';s += to_string(a - b);}else if(temp == "c"){s += to_string(a);s += '*';s += to_string(b);s += '=';s += to_string(a * b);}ysf = temp;}else{a = stoi(temp);cin >> b;if(ysf == "a"){s += to_string(a);s += '+';s += to_string(b);s += '=';s += to_string(a + b);}else if(ysf == "b"){s += to_string(a);s += '-';s += to_string(b);s += '=';s += to_string(a - b);}else{s += to_string(a);s += '*';s += to_string(b);s += '=';s += to_string(a * b);}}cout << s << endl;cout << s.size() << endl;}return 0;
}
💯老师的做法
老师的做法与我的实现思路相似,但有一些不同之处。老师的代码在结构上稍显复杂,特别是在输入和字符串拼接部分的处理上,且做了更多的优化来处理继承运算符的情况。
代码实现:
int main()
{int n = 0;cin >> n;string op;string num1;string num2;string last;int ret = 0;while (n--){string ans;cin >> op;if (op == "a" || op == "b" || op == "c"){cin >> num1 >> num2;int n1 = stoi(num1);int n2 = stoi(num2);ans += num1;if (op == "a"){ret = n1 + n2;ans += "+";}else if (op == "b"){ret = n1 - n2;ans += "-";}else{ret = n1 * n2;ans += "*";}last = op;}else{num1 = op;cin >> num2;int n1 = stoi(num1);int n2 = stoi(num2);ans += num1;if (last == "a"){ret = n1 + n2;ans += "+";}else if (last == "b"){ret = n1 - n2;ans += "-";}else{ret = n1 * n2;ans += "*";}}ans += (num2 + "=" + to_string(ret));cout << ans << endl;cout << ans.size() << endl;}return 0;
}
💯对比分析
-
结构差异:
- 我的做法中,我们根据输入的运算符判断是否更新运算符,并且用
last_op
来记住上一题的运算符,保证后续算式的正确计算。 - 老师的做法稍微复杂一些,采用了更显式的变量存储(如
last
变量)。另外,老师在每次处理完一个算式后,拼接完成的字符串才会输出。
- 我的做法中,我们根据输入的运算符判断是否更新运算符,并且用
-
字符串拼接:
- 我的做法通过直接将
+
、-
、*
等运算符拼接进ans
字符串。 - 老师的做法在拼接过程中,将运算符的插入和结果的转换更加细化,也做了更精确的类型转换处理(使用
stoi
将字符串转换为整数)。
- 我的做法通过直接将
-
处理继承运算符:
- 我的做法是依赖
last_op
来判断是否使用上一题的运算符。 - 老师的做法在这一点上比较细致,利用了
last
变量来确保后续运算使用的是正确的运算符。
- 我的做法是依赖
💯拓展与优化
-
代码优化:
- 对于运算符和结果拼接部分,使用了
+=
拼接字符串,但如果问题较为复杂或涉及到更多操作,可能会导致拼接效率不高。可以考虑使用ostringstream
来拼接字符串,这样可以提高性能。
- 对于运算符和结果拼接部分,使用了
-
用户输入优化:
- 可以增加输入校验,避免用户输入错误的数据类型(如非数字输入等)。
-
更广泛的应用:
- 这类算术问题不仅限于加法、减法和乘法。如果要处理更多运算符(如除法、取余等),可以通过扩展运算符判断来完成。
-
函数化:
- 该问题的不同部分(如运算符判断、算式拼接、输出结果等)可以通过函数化进行封装,提高代码的模块化和复用性。
💯总结
本次学习和讨论了如何用 C++ 语言处理简单的口算算式,通过两种不同的实现方法(我的做法与老师的做法),我们掌握了如何判断运算符、处理继承运算符的情况,并输出结果与算式的总长度。通过对比分析,我们看到了两种做法的异同与各自的优缺点。
在优化方面,我们提出了改进的思路,如何提高代码性能、增强可扩展性,以及如何处理更多复杂的运算符类型。总体来说,这道题目的解决方案为我们提供了一个很好的编程练习机会,帮助我们更好地理解字符串操作、控制流程和输入输出的细节。
一开始的错误做法
#include <iostream>
#include <string>
using namespace std;int main()
{int i = 0;cin >> i;int opera = 0;string s;while(i--){int index = 0, a = 0, b = 0;while(cin >> s){index++;if(index == 1){if(s[i] == 'a')opera = 1;else if(s[i] == 'b')opera = 2;else if(s[i] == 'c')opera = 3;elsea = stoi(string(1, s[i])); // 将字符 s[i] 转换为字符串后再使用 stoi}if(index == 2 && a != 0)b = stoi(string(1, s[i]));else if(index == 2 && a == 0)a = stoi(string(1, s[i]));if(index == 3)b = stoi(string(1, s[i])); }if(opera == 1)cout << a << "+" << b << "=" << (a + b) << endl;else if(opera == 2)cout << a << "-" << b << "=" << (a - b) << endl;elsecout << a << "*" << b << "=" << (a * b) << endl;}return 0;
}
还有,要注意变量的作用域
学习C++的建议
C++ 是一门强大且广泛应用的编程语言,无论是系统开发、游戏开发还是高性能计算,它都有不可替代的地位。然而,学习C++的道路可能是陡峭的,为了帮助你更高效地掌握这门语言,我总结了一些学习建议和经验。
1. 理解C++的基础
学习重点:
- 掌握基本语法:
- 学会声明变量、条件语句、循环、函数等核心语法。
- 掌握数组、指针、引用等基础知识。
- 熟悉标准输入输出:
- 掌握
cin
和cout
的用法。 - 理解格式化输出,例如
std::setw
和std::fixed
。
- 掌握
- 记住编译器的角色:
- 理解源代码如何通过编译器转换为可执行程序,选择一款好的IDE(如Visual Studio、Clion、VSCode)。
建议:用大量小程序练习这些基础语法,比如写一个计算器、模拟猜数字游戏等。
2. 深入学习C++的特性
学习重点:
- 面向对象编程(OOP):
- 理解类和对象,熟悉如何定义类、成员变量和成员函数。
- 掌握封装、继承、多态三大核心特性。
- 内存管理:
- 理解指针的用法,掌握动态内存分配(
new
和delete
)。 - 学习如何避免内存泄漏,熟悉智能指针(如
std::unique_ptr
和std::shared_ptr
)。
- 理解指针的用法,掌握动态内存分配(
- 标准模板库(STL):
- 熟悉常用的容器(如
vector
、map
、set
)和算法(如sort
、find
)。 - 掌握迭代器的用法。
- 熟悉常用的容器(如
- 异常处理:
- 学习使用
try-catch
块处理异常。 - 理解异常的用途以及如何设计健壮的代码。
- 学习使用
建议:尝试开发一个小型项目,比如一个学生管理系统,综合应用类、STL、指针和动态内存分配。
3. 掌握进阶内容
学习重点:
- 模板:
- 理解函数模板和类模板,掌握泛型编程思想。
- 学习模板特化和模板元编程的基本概念。
- 多线程与并发:
- 学习 C++11 提供的多线程支持(如
std::thread
)。 - 熟悉互斥锁(
std::mutex
)和条件变量(std::condition_variable
)。
- 学习 C++11 提供的多线程支持(如
- C++与C的兼容性:
- 学习如何在C++中使用C语言代码,理解C和C++的区别。
- 掌握C风格字符串(
char[]
)和C++字符串(std::string
)的转换。
建议:在这一阶段,可以挑战更复杂的项目,比如开发一个小型的HTTP服务器,学习网络编程并结合多线程。
4. 学习资源与实践方法
学习资源:
- 书籍:
- 《C++ Primer》:非常适合初学者的经典书籍。
- 《Effective C++》:进阶学习C++最佳实践的指南。
- 《The C++ Programming Language》:Bjarne Stroustrup(C++之父)的权威著作。
- 在线课程:
- Coursera 上的 C++ 编程课程。
- YouTube 上免费的 C++ 系列教程。
- 社区与文档:
- 参与C++相关的论坛(如CSDN、Stack Overflow)。
- 阅读官方文档(https://en.cppreference.com)。
实践方法:
- 多写代码,多调试:
- 每学一个概念后,写至少两个示例代码并进行调试。
- 做小项目:
- 从简单的控制台程序开始,比如文件读写、计算器、小游戏等。
- 慢慢过渡到图形界面或网络程序开发。
- 阅读他人代码:
- 阅读开源项目的代码,理解优秀代码的设计思路。
- 参加编程比赛:
- 比如 LeetCode 或 Codeforces,可以帮助你提升算法能力和C++的熟练度。
5. 保持耐心与兴趣
学习C++可能会面临以下困难:
- 复杂的语法:如模板、智能指针、多线程等。
- 调试困难:指针错误、内存泄漏、未定义行为可能让人头疼。
如何应对:
- 将大问题拆解成小问题,逐步解决。
- 不断重复基础知识,以加深理解。
- 保持兴趣,尝试一些有趣的项目,比如写一个游戏、制作一个简单的图形程序。
小结
学习C++需要一个循序渐进的过程,从基础语法到面向对象编程,再到进阶的模板和并发编程,每一步都需要耐心和实践。通过充分利用学习资源、进行大量编码练习,以及挑战实际项目,你一定可以成为C++的高手。记住,学习的核心在于理解,而非死记硬背。
祝你学有所成,享受C++编程的乐趣!