这是前两节课:
-----------------------------------------------------------
格式化?是printf吗?
不是啦,上一节已经能够计算出给定的4个数,如何计算出24点,只是在答案输出上,有点不爽,比如:5,10,2 ,6四个数,上节课我们输出的答案是:5+10*2-6。 仔细 一算,这答案5+20-6,就是19嘛。这一节课的任务很简单,就是让它能够正确地输出为:(5+10)*2-6.
问题关键显然是在加括号上,怎么实现?从运算符号下手,上例中,第一个运算符是+号,第二个则是*,后面的运算符优先级大于前面的,而按照上一节提到“连贯式”的意义,我们要的是前面的运算先处理,所以必须给前面的计算加括号。
新加exp_getter.h 和 exp_getter.cpp 到项目中。
exp_getter.h
- #ifndef EXP_GETTER_H_INCLUDED
- #define EXP_GETTER_H_INCLUDED
- #include <string>
- #include "common_def.h"
- //组装连续运算形式的表达式:
- std::string get_consecutive_exp(int opds[4], operator_index oprs[3]);
- //组装分割运算形式的表达式:
- std::string get_separate_exp(int opds[4], operator_index oprs[3]);
- #endif // EXP_GETTER_H_INCLUDED
代码文件没有什么好废话的。头文件中就是声明了两个函数,一个函数用来为“连贯式”计算的结果格式化,一个为“分割式”计算的结果格式化——等等,我们还没有讲为“分割式”结果格式化的思路呢?这个太简单了,留给大家先自行看代码再说吧。
exp_getter.cpp,片段一
- #include <sstream> //for stringstream
- #include "exp_getter.h"
- using namespace std;
- void add_parenthesis(stringstream& ss)
- {
- ss.str("(" + ss.str() + ")");
- ss.seekp(0, ios_base::end);
- }
这是给一个字符串加上一对括号的。为了其它一些地方的操作方便,我用的是 stringstream流。如果你不熟悉,那是时候熟悉这家伙了,它是C++ 标准库中一个最常用的家伙。
一定要注意哦,这个流将被我们“又读又写”,此时就是“写”,为了保证后续还有的写操作写入位置正确,我们在改变它的内容(这是写入操作)之后,将写的位置,强置到流最后面。
exp_getter.cpp,片段二
继续前面的代码,这是实现格式“连贯式”计算的函数。
- string get_consecutive_exp(int n[4], operator_index o[3])
- {
- stringstream ss;
- //12*2-12*2 ==> (12 * 2 - 12) * 2
- //2+1*4*2 ==> (2+1)*4*2
- //2*2+8*2 ==> (2*2+8)*2
- ss << n[0] << operator_char_def[o[0]] << n[1];
- if(o[0] < 2 && o[1] >= 2)
- add_parenthesis(ss);
- ss << operator_char_def[o[1]] << n[2];
- if (o[1] < 2 && o[2] >= 2)
- add_parenthesis(ss);
- ss << operator_char_def[o[2]] << n[3];
- return ss.str();
- }
n[4]是4张牌的牌面值(再自我检讨一下,入参中的4,不过是用来好看的,根本不起作用,而函数中的代码也没有检查任何数组戴的问题)。 operator_index[3] 则是结果表达式中的那三个操作符(再再自我检讨一下,入参中的3……)。
由于我们是用 0,1,2,3,分别表示“+”,"-","*","/"。所以下面的这个if语句:
if (o[1] < 2 && o[2] >= 2)
它在判断什么呢? 其实就是:如果 第1个运算符是加或减,并且第二个运算符是乘或除,则需要进行加括号处理,比如答案是:
1 + 3 * 5 + 4 ,则——
上述代码第14行,通过流操作,得到:1+3。
然后第17行,得到 (1+3)
再往后的判断逻辑一样。本例中由于*比+优先级高,所以后面判断结果不需要再添加括号,最终结果就是(1+3)*5+4。
会不会忘记 operator_char_def 数组是什么东西?直接说下,免得非要查前面的课程: operator_index 存的是0,1,2,3,用来表示加减乘除,而operator_char_def 才是真正存着 “+,-,*,/”四个字符。
exp_getter.cpp,片段三
继续前面代码,这是实现“分割式”计算结果的格式化函数:
- string get_separate_exp(int n[4], operator_index o[3])
- {
- stringstream ss;
- //3*4+4*3 ==> (3*4) + (4*3)
- ss << '(' << n[0] << operator_char_def[o[0]] << n[1] << ')'
- << operator_char_def[o[1]]
- << '(' << n[2] << operator_char_def[o[2]] << n[3] << ')';
- return ss.str();
- }
它简单多了,因为我们是强制加括号,正如代码那行注释,理论是不需要括号的,但我们为了简化处理,就强制添加了。
有了以上两个函数,回到 calc_24.cpp文件,开始处增加一行:
#include "exp_getter.h"
然后在 bool calc_24(int num[4]) 函数,找到合适的位置,替换原来输出的那两个处代码,编译通过就完成了。现在,我们的输出漂亮极了。下面是实例:
输入: 12 9 9 3, 输出:(12-9)*9-3。
输入:4 5 6 7 ,输出: (5+7-6)*4。
-------------------------------------------------------------------------------
如果您想与我交流,请点击如下链接成为我的好友: