1.用c和c++下用栈实现数的进制转换
method1: C的实现
method2: 用c++类的实现
发现上述两种方法只是实现了10进制向2进制的转换,不难发现很容易将上述方法应用到10进制向x进制的转换(x<=10),由于栈的类型是唯一的,若要扩展到10+x进制,还需要进行适当的改进。
对c的实现方法,只需将stackEle改为char,预先定义一个char m[] = "0123456789ABCDEF";,就可以解决问题了;对类的实现方法,也是只要做类似的改进。
2. 用栈实现一个小的计算器
主要是要考虑括号和优先级。将中序形式的输入转换为后序形式,也称为逆波兰表示(RPN)。
2.1 中序表达式转为后序表达式的直观方法
A:扫描中序表达式,碰到操作数(operand)后放入结果串中。
B:碰到操作符(operator)时,如果能确认其操作数,将操作数放入结果串中,否则,将操作符压入栈中。到表达式最后,将栈中的剩余操作符出栈。
拿a+b*c举例:首先a放入结果串中,+入栈,b放入结果串后结果成为ab,遇到*,*的优先级比+大,*入栈,这时栈中为+*,最后C放入结果串,成为abc,扫描到结尾了,将栈中操作符+*按LIFO的原则出栈,最终的结果为:abc*+
2.2 利用后序表示计算的方法
A:例如4+3*5,后序表示是4 3 5 * +:计算时采用这样的方法:
- 将操作数435依次压入栈
- 读到操作符*时,计算栈顶两操作数3 5在*下的结果,将结果15压入栈中,此时栈中元素为4 15
- 读取+,计算4+15,将结果19压入栈
- 扫描接触,19即是结果
B:类的设计
2.3中序表示式转后序
由于计算机器的面向对象是人,输入的时候不能让一个不会计算机的人输入他要求的式子的后序形式,因而必须设计一种算法,能够自动根据中序输入得到其相应的后序形式,这样,再调用上面的类进行计算时就可以得出结果了。
在中序转后序时,主要是要考虑运算符的个数、优先级(precedence)、结合性(associativity)等。
为了简化计算,仅对含二元操作符的表达式进行讨论。那么,对这样的表达式,若对操作数赋权1,操作符赋权-1,则一个正确输入的中序表达式的权值累加和应该为1,且在中间的任何一个累加点,累加和都应该介于0,1两值(因为二元操作符时,操作数的数目总比操作符数目多1)。
A 算法设计中应该要考虑到的问题
- 运算符优先级问题:如a*b+c,解决这个问题的方式是对运算符赋予栈优先级,将操作数添加到结果串中,运算符入栈,入栈时,如果栈顶元素的运算符优先级要大于当前元素的有限级,则栈顶元操作符要出栈,放入结果串中,例如当遇到+时,+<*,因而结果串为ab*,栈内为+,最后为ab*+。
- 解决^(指数计算符)等具有右结合性的元素的问题:如a^b^c=(a^(b^c))!=(a^b)^c,方法是给每个运算符再增加一个输入有限级,右结合性运算符的输入优先级大于其栈优先级,其它非右结合性运算符的输入优先级等于其栈优先级,这样,我们只要比较当前待压入栈的运算符的输入优先级和栈顶元素的栈优先级就可以确定一个运算符是否入栈的问题了,比如,如果新来操作符的栈优先级大于或等于栈顶运算符的栈优先级,则新来操作符入栈;否则,栈顶元素出栈。这将运算符的优先级的问题同时考虑进来了。
- 解决括号的问题:在原来的基础上,将左括号的输入优先级设为最大,栈优先级设为最小,这样,碰到左括号时,左括号总是要继续入栈,左括号后的操作符也总要继续入栈,剩下的规则沿用上面的,直到出现右括号时,才将左括号之前的操作符依次出栈,并丢弃左括号。
优先级设置:
符号 输入优先级 栈优先级 rank值
+ - 1 1 -1
*/% 2 2 -1
^ 4 3 -1
( 5 -1 0
) 0 0 0
B类的设计
参考文献
[1] K&R The C Programming Language (the second edition)
[2] 《c++编程风格》(c++ programming style )作者 Tom Cargill 译者 聂雪军 机械工业出版社2007.1
[3] Data Structures with C++ using STL, 2nd Edition William H. Ford William R. Topp
类的设计程序来自文献[3]