栈在表达式求值中的应用
算数表达式:操作数、运算符、界限符
逆波兰表达式=后缀表达式
波兰表达式=前缀表达式
中缀转后缀
的手算方法
:(后缀表达式不唯一)
1.确定中缀表达式中各个运算符的运算顺序
2.选择下一个运算符,按照[左操作数 右操作数 运算符]
的方式组合成一个新的操作数
3.如果还有运算符没被处理,就继续2
私房菜:“左优先”原则,不要FreeStyle,保证手算和机算结果相同
“左优先”原则:
只要左边的运算符能先计算,就优先算左边的
中缀转后缀
的手算方法
:(后缀表达式唯一)
1.确定中缀表达式中各个运算符的运算顺序
2.选择下一个运算符,按照[左操作数 右操作数 运算符]
的方式组合成一个新的操作数
3.如果还有运算符没被处理,就继续2
4.“左优先”原则:
只要左边的运算符能先计算,就优先算左边的
中缀表达式转后缀表达式的机算方法:
初始化一个栈,用于保存暂时还不能确定运算顺序的运算符
。
从左到右处理各个元素,直到末尾。可能遇到三种情况:
1.遇到操作数
。直接加入后缀表达式。
2.遇到界限符
。遇到“(”直接入栈;遇到“)”则依次弹出栈内运算符并加入后缀表达式,直到弹出“(”为止。注意“(”不加入后缀表达式。
3.遇到运算符
。依次弹出栈中优先级
高于或等于当前运算符的所有运算符,并加入后缀表达式,若碰到“(”或栈空则停止。之后再把当前运算符入栈。
按上述方法处理完所有字符后,将栈中剩余运算符依次弹出,并加入后缀表达式
void middleToLast(char middle[], int length, SqList &L){
SqStack S;
initStack(S);
for(int i = 0; i < length; i++){
if(middle[i] == "("){//界限符处理
push(S,middle[i]);
}else if(middle[i] == ")"){//界限符处理
char topElem = getHeadElem(S);
while(topElem != "("){
pop(S, topElem);
listInsert(L, topElem);
}
if(topElem == "("){
pop(S, topElem);
}
}else if(middle[i] == "+" || middle[i] == "-" || middle[i] == "*" || middle[i] == "/"){//操作符处理
char topElem = getHeadElem(S);
while(operatorPriority(middle[i],topElem) && topElem != "(" && !stackEmpty(S)){
pop(S, topElem);
listInsert(L, topElem);
}
push(S, middle[i]);
}else{//操作数处理
listInsert(L, middle[i]);
}
}
if(!stackEmpty(S)){
char topElem;
pop(S, topElem);
listInsert(L, topElem);
}//循环完后栈非空时的处理
return;
}
//判读运算符a的优先级是否不大于运算符b的优先级
bool operatorPriority(char a, char b){
if((a == "+" || a == "-") && (b == "+" || b == "-" || b == "*" || b == "/")){
return true;
}else{
return false;
}
}
后缀表达式的手算方法:
从左往右扫描,每遇到一个运算符,就让运算符前面最近的两个操作数
执行对应运算,合体为一个操作数
注意:两个操作数的左右顺序
后缀表达式的机算方法:(用栈(用于存放当前暂时还不能确定运算次序的操作数)实现
后缀表达式的计算)
1.从左往右扫描下一个元素,直到处理完所有元素
2.若扫描到操作数则压入栈,并回到1;否则执行3
3.若扫描到运算符,则弹出两个栈顶元素,执行相应运算(注意:先出栈的是“右操作数”
),运算结果压回栈顶,回到1
int lastCalculation(SqList L){
for(int i = 0; i < L.length; i++){
if(L.data[i] == "+" || L.data[i] == "-" || L.data[i] == "*" || L.data[i] == "/"){
char topElem1,topElem2;
pop(S, topElem2);
pop(S, topElem1);
int temp = calculate(topElem1, topElem2, L.data[i]);
}else{
push(S,(int)L.data[i]);
}
}
return getHeadElem(S);
}
//计算
int calculate(int topElem1, int topElem2, char operate){
if(operate == "+"){
result1 = topElem1 + topElem2;
return result1;
}
if(operate == "-"){
result2 = topElem1 - topElem2;
return result2;
}
if(operate == "*"){
result3 = topElem1 * topElem2;
return result3;
}
if(operate == "/"){
result4 = topElem1 / topElem2;
return result4;
}
}
后缀转中缀的手算方法:前面的逆过程
中缀转前缀
的手算方法:
(前缀表达式唯一)
1.确定中缀表达式中各个运算符的运算顺序
2.选择下一个运算符,按照[运算符 左操作数 右操作数]
的方式组合成一个新的操作数
3.如果还有运算符没被处理,就继续2
4.“右优先”原则:
只要右边的运算符能先计算,就优先算右边
的
前缀表达式的机算方法:(用栈实现前缀表达式的计算)
1.从右往左
扫描下一个元素,直到处理完所有元素
2.若扫描到操作数则压入栈,并回到1;否则执行3
3.若扫描到运算符,则弹出两个栈顶元素,执行相应运算(注意:先出栈的是“左操作数”
),运算结果压回栈顶,回到1
在这里插入代码片
中缀表达式的计算(用栈实现)
中缀转后缀+后缀表达式求值两个算法的结合
用栈实现
中缀表达式的计算:
初始化两个栈,操作数栈
和运算符栈
若扫描到操作数,压入操作数栈
若扫描到运算符或界限符,则按照“中缀转后缀”相同的逻辑压入运算符栈(期间也会弹出运算符,每当弹出一个运算符时,就需要再弹出两个操作数栈的栈顶元素并执行相应运算,运算结果再压回操作数栈
)
在这里插入代码片