简单表达式求值
迷宫求解问题
简单表达式求值:
存储方式:顺序栈。
简单表达式:只包含加减乘除括号和数字的表达式。
中缀表达式:运算符位于两个操作数之间的表达式。
后缀表达式:运算符位于两个操作数之后的表达式。
前缀表达式:运算符位于两个操作数前面。
用字符数组exp来储存中缀表达式,用postexp字符数组来存储后缀表达式,运算符的临时存储以及优先级的处理通过运算符栈来处理。
例如对于中缀表达式“1 + 2+ 3”,扫描exp字符数组,首先把1存入postexp,然后扫描到了第一个+号,此时运算符栈里面没有运算符,那么直接存入运算栈,继续扫描,把2放入postexp,继续,之后遇到第二个运算符,也是加号,根据后缀表达式的定义,此时前面已经有两个数字了,所以postexp的第三个元素一定是一个运算符,这时候需要比较两个运算符的优先级了,很明显,对于同级的+运算,我们是从左到右运算的,所以此时应该把栈里面的+弹出,放到postexp中去,然后把第二个+存入运算符栈,其实还可以这样子理解:第二个+是在2和3中间的,又根据后缀表达式知,此时的运算符不能够是第二个+,第二个+应该是在3之后出现,所以postexp的第三个运算符一定是最先存入运算符栈的那个元素。
在扫描exp遇到一个运算符op时,如果栈为空,直接将其进栈,如果栈不空,
只有当op的优先级高于栈顶运算符的优先级时才直接将op进栈(op先出栈表示
先执行它);否则依次出栈运算符并存入postexp(出栈的运算符都比op先执行),
知道栈顶运算符的优先级小于op的优先级为止,然后将op进栈。
再来一个带有括号的例子:”2 * (1 + 3) -4",扫描exp数组,首先把2存入postexp,然后进栈*,遇到左括号“(”,其代表一个子表达式的开始,直接进栈,把1存入postexp,进栈+,把3存入postexp,下一步会扫描到右括号“)”,这代表一个子表达式的结束,把存储在左括号上面的运算符“+”出栈,放入postexp,出栈“(”,因为此时“(”已经没有用处,这时候扫描到了“-”,这时候在栈中的“*”的优先级高于“-”,所以“*”出栈,放入到postexp中,“-”入栈,4放入postexp中,扫描完毕,把剩下的运算符一一出栈,存入到postexp中。
在扫描exp遇到一个运算符op时,如果op为“(”,表示一个子表达式的开始,直接将其进栈;如果
op为“)”,表示一个子表达式的结束,则要出栈运算符并存入postexp直到栈顶元素为“(”,再将
“(”出栈;如果op是其他运算符,而栈顶为“(”,直接进栈。
把中缀表达式转化为后缀表达式的基本思想就是:
从左到右扫描中缀表达式exp,每扫一次当做一次循环,只有把每个数字或者是符号都彻底处理完了以后(比如把数字放到了postexp后缀表达式数组,把符号放到了运算符链栈里面)才进行下一个循环。对于每一次扫描,
若扫描到了数字,那么就把该数字放到postexp后缀表达式数组里面,当然这个数字可能不是单独的,他可能是一个数字的十位上的数,所以我们需要把后面连着的所有数字也同样放到postexp里面,直到扫描到的不是数字为止。由于数组是连续存储的我们不知道’1’'2‘表示的是12还是1和2,所以需要在数字放入完成之后加一个标志结束符’#‘
若扫描到了加号和减号,那么由于这中符号的优先级在四个符号中最低,所以前面的运算需要先进行,若没有左括号则全部pop出,并依次放到poestexp中直到栈空。比如说如果扫描到了加号或减号,这时候我们需要进运算符栈,但是在此之前,如果符号栈里面有加号,后缀表达式数组里面有两个数字‘1’和 ‘2’,这时按照运算法则,我们是不能先算后面的加法的,也就是不可能先算‘2’+‘x’的,所以符号栈里面的加号一定要先出去,然后再把扫描到符号的进栈,同样的对于左括号上的运算符也是如此,需要全部pop出,依次放到postexp中,直到栈顶元素是’(‘。理解这些话需要不断的在纸上写实例,让自己理解算法的过程,在纸上写实例写多了就会理解的。这是一种理解算法的很好的方法。
若扫描到了乘号和除号,若没有左括号,则pop运算符并放入postexp直到栈顶元素是加减符号或栈空,若有左括号,则pop运算符并放入postexp直到栈顶元素是加减符号或左括号。
若扫描到了左括号,那么直接进栈。
若扫描到了右括号,标志一个子表达式的结束,需要把在左括号前的全部运算符pop出,放到postexp中,然后把左括号也pop出,但是不放入postexp。
#include <stdio.h>
#include <malloc.h>
#define maxsize 100
typedef char Elemtype;
typedef struct LinkSt
{
Elemtype signal;
struct LinkSt *next;
} LinkStNode;
typedef struct
{
Elemtype data[maxsize];
int top;
} SqStack;
LinkStNode* InitLinkStack()
{
LinkStNode *s;
s = (LinkStNode *)malloc(sizeof(LinkStNode));
s -> next = NULL;
return s;
}//初始化一个链栈
SqStack* InitSqStack()
{
SqStack *s;
s = (SqStack *)malloc(sizeof(SqStack));
s -> top = -1;
return s;
}//初始化一个顺序栈
Elemtype GetElem(LinkStNode *SignalStack)
{
Elemtype e;
e = SignalStack -> next -> signal;
return e;
}
Elemtype Pop(LinkStNode *SignalStack)
{
Elemtype e;
e = SignalStack -> next -> signal;//取出元素
LinkStNode *p;
p = SignalStack -> next;
SignalStack -> next = p -> next;
free(p);
p = NULL;//删除栈顶元素
return e;
}
_Bool judge(Elemtype e)
{
if (e == '(') return 0;
else return 1;
}
void PushLink(LinkStNode *SignalStack,Elemtype e)
{
LinkStNode *s;
s = (LinkStNode *)malloc(sizeof(LinkStNode));
s -> signal = e;
s -> next = NULL;
if (SignalStack -> next != NULL) s -> next = SignalStack -> next;
SignalStack -> next = s;
}
void PushSq(SqStack *postexp,Elemtype e)
{
postexp -> top ++;
postexp -> data[postexp -> top] = e;
}//把运算符进栈postexp
SqStack* trans(char exp[maxsize])
{
SqStack *postexp;
postexp = InitSqStack();//创建一个顺序栈postexp
LinkStNode *SignalStack;
SignalStack = InitLinkStack();//创建一个链栈signalstack
int i = 0;
while(exp[i] != '\0')
{
switch (exp[i])
{
case '+':
case '-':
while(SignalStack -> next != NULL && GetElem(SignalStack) != '(')
{
Elemtype n;
n = Pop(SignalStack);
PushSq(postexp,n);
}
PushLink(SignalStack,exp[i]);
i ++;
break;
case '*':
case '/':
while (SignalStack -> next != NULL &&GetElem(SignalStack) != '(' && GetElem(SignalStack) != '+' && GetElem(SignalStack) != '-')
{
Elemtype n;
n = Pop(SignalStack);
PushSq(postexp,n);
}
PushLink(SignalStack,exp[i]);//把乘号除号放进去
i ++;
break;
case '(':
PushLink(SignalStack,exp[i]);
i ++;
break;
case ')':
do
{
Elemtype n;
n = Pop(SignalStack);
PushSq(postexp,n);
}while(GetElem(SignalStack) != '(');
Elemtype n;
n = Pop(SignalStack);//去掉左括号
i ++;
break;
default:
do
{
PushSq(postexp,exp[i]);
i ++;
}while(exp[i] >= '0' && exp[i] <= '9');//输入数字字符
Elemtype k = '#';
PushSq(postexp,k) ;
}
}
while(SignalStack -> next != NULL)
{
Elemtype n;
n = Pop(SignalStack);
PushSq(postexp,n);
}
postexp -> top ++;
postexp -> data[postexp -> top] = '\0';
return postexp;
}
int main()
{
int i = 0;
char exp[maxsize];
do
{
scanf("%c", &exp[i]);
}while (exp[i ++] != '\n'); exp[i-1]='\0';//输入字符串成功。
SqStack *postexp = trans(exp);//转化为后缀表达式
printf("%s", *postexp);
return 0;
}