正常的表达式 逆波兰表达式
a+b --->a,b,+
a+(b-c) --->a,b,c,-,+
a+(b-c)d --->a,d,b,c,-,,+
a=1+3 --->a=1,3 +
http=(smtp+http+telnet)/1024 写成什么呢?
http=smtp,http,telnet,+,+,1024,/
逆波兰表达式是一种十分有用的表达式,它将复杂表达式转换为可以依靠简单的操作得到计算结果的表达式。例如(a+b)(c+d)转换为ab+cd+
它的优势在于只用两种简单操作,入栈和出栈就可以搞定任何普通表达式的运算。其运算方式如下:
如果当前字符为变量或者为数字,则压栈,如果是运算符,则将栈顶两个元素弹出作相应运算,结果再入栈,最后当表达式扫描完后,栈里的就是结果。
将一个普通的中序表达式转换为逆波兰表达式的一般算法是:
(1)首先构造一个运算符栈,此运算符在栈内遵循越往栈顶优先级越高的原则。
(2)读入一个用中缀表示的简单算术表达式,为方便起见,设该简单算术表达式的右端多加上了优先级最低的特殊符号“#”。
(3)从左至右扫描该算术表达式,从第一个字符开始判断,如果该字符是数字,则分析到该数字串的结束并将该数字串直接输出。
(4)如果不是数字,该字符则是运算符,此时需比较优先关系。
做法如下:将该字符与运算符栈顶的运算符的优先关系相比较。如果,该字符优先关系高于此运算符栈顶的运算符,则将该运算符入栈。倘若不是的话,则将栈顶的运算符从栈中弹出,直到栈顶运算符的优先级低于当前运算符,将该字符入栈。
(5)重复上述操作(3)-(4)直至扫描完整个简单算术表达式,确定所有字符都得到正确处理,我们便可以将中缀式表示的简单算术表达式转化为逆波兰表示的简单算术表达式。
下面是程序化算法流程:
1、建立运算符栈stackOperator用于运算符的存储,压入'\0'。
2、预处理表达式,正、负号前加0(如果一个加号(减号)出现在最前面或左括号后面,则该加号(减号)为正负号) 。
3、顺序扫描表达式,如果当前字符是数字(优先级为0的符号),则直接输出该数字;如果当前字符为运算符或括号(优先级不为0的符号),则判断第4点 。
4、若当前运算符为'(',直接入栈;
若为')',出栈并顺序输出运算符直到遇到第一个'(',遇到的第一个'('出栈但不输出;
若为其它,比较stackOperator栈顶元素与当前元素的优先级:
如果 栈顶元素 >= 当前元素,出栈并顺序输出运算符直到 栈顶元素 <当前元素,然后当前元素入栈;
如果 栈顶元素 <当前元素,直接入栈。
5、重复第3点直到表达式扫描完毕。
6、顺序出栈并输出运算符直到栈顶元素为'\0'。
各运算符及符号优先级:
'\0': -1
')': 1
'(': 2
'+'、'-': 3
'*'、'/'、'%': 4
'^': 5
其它: 0
/**
* 计算逆波兰表达式的值
*/
function calculate(RPolishArray){
var result = 0
var tempArray = new Array(100)
var tempNum = -1
for(i = 0i <RPolishArray.lengthi++){
if(RPolishArray[i].match(/\d/)){
tempNum++
tempArray[tempNum] = RPolishArray[i]
}else{
switch(RPolishArray[i]){
case '+':
result = (tempArray[tempNum-1] *1) + (tempArray[tempNum] * 1)
tempNum--
tempArray[tempNum] = result
break
case '-':
result = (tempArray[tempNum-1] *1) - (tempArray[tempNum] * 1)
tempNum--
tempArray[tempNum] = result
break
case '*':
result = (tempArray[tempNum-1] *1) * (tempArray[tempNum] * 1)
tempNum--
逆波兰表达式的算法1、输入一个字符串,将其格式化的储存在一个数组中,以方便的记录表达式中数和各个符号的出现顺序
约定在数组中记录时,每个数或符号用两个整数来记录
第一个整数记录该位是什么东西,0表示是一个数,1表示是括号,2表示反括号,3、4、5、6分别表示乘除加减号
如果该位是一个数,那么第二个整数记录着个数的具体取值,否则记录该位的符号的ASCII码
比如字符串"(1-23)"会被转化成二位数组{ {1,'('} , {0,1} , {6,'-'} , {0,23} , {2,')'}}
这个转化过程每什么技巧性,对原字符串各位顺次判断并处理即可
原先的字符串中可能出现一元运算符正号'+'和负号'-',为了处理方便,一律在其前面加个0,改写成"0+..."或者"0-..."
另外为了之后转化逆波兰表达式方便,处理过程中会在转化出的数组的首尾一律添加一对括号
2、将之前所提到的格式数组转化为逆波兰表达式
约定依然用二位数组记录一个逆波兰表达式,并且格式与之前的数组相同,除了没有括号以外
比如逆波兰表达式 1 2 - 35 +,会被记录成{ {0,1} , {0,2} , {6,'-'} , {0,35} , {5,+}}
转化时,需要用一个栈
具体转化操作如下:
顺次处理格式数组的每一位,对其作判断
如果该位是一个数或者是括号'(',,将其入栈
如果该位是乘号'*'或者除号'/',不断进行出栈操作直到栈顶元素是个括号'('或者加号'+'或者减号'-',然后将这个乘号或者除号入栈
如果该位是加号'+'或者减号'-',不断进行出栈操作直到栈顶元素是个括号'(',然后将这个加号或者减号入栈
如果该位是反括号')',那么不断进行出栈操作直到有一个括号'('出栈
在上述操作中,所有的出栈元素,除了括号'('以外,都被顺次添加到所要生成的逆波兰表达式的末尾
这样就转化出了一条逆波兰表达式
3、对逆波兰表达式求值
求值时,也需要用到一个栈
求值步骤如下:
顺次处理逆波兰表达式的每一位,对其作判断
如果该位是一个数,将这个数入栈
如果该位是一个运算符,那么连续进行两次出栈操作,可以得到栈顶的两个元素,对这两个元素用该位的运算符做运算,将所得的结果入栈
比如,如果当时栈顶元素是3,次栈顶的元素是2,运算符是减号'-',那么连续两次出栈得到3和2两个元素,再将2-3的运算结果1入栈
注意有些运算符(减号和除号)不符合交换律,因此运算时必须是次栈顶元素在前、栈顶元素在后,顺序不能反
当每一位都处理完了之后,只要输入的是一个合法的逆波兰表达式,必然栈中只剩下一个元素,这个元素就是逆波兰表达式求值的结果