1. 简单回顾
笔者认为该算法,只需要记住流程,而记住流程的关键就是多做几个笔试选择题,比如
牛客网:
可以完全按照中缀表达式转换成后缀表达式的算法来:
步骤 | 栈 | 后缀表达式 |
---|---|---|
遇到X输出 | 空 | X |
遇到=入栈 | = | X |
遇到A输出 | = | XA |
遇到A输出 | = | XA |
遇到+,比=优先级高,入栈 | =+ | XA |
遇到B输出 | =+ | XAB |
遇到*,比+优先级高,入栈 | =+* | XAB |
遇到(,直接入栈 | =+*( | XAB |
遇到C输出 | =+*( | XABC |
遇到-,栈顶是(,入栈 | =+*(- | XABC |
遇到D输出 | =+*(- | XABCD |
遇到),将栈直到(的运算符全部抛出,并丢弃() | =+* | XABCD- |
遇到/,栈顶是*,直接抛出*,接着遇到+,优先级比/低,入栈/ | =+/ | XABCD-* |
遇到E输出 | =+/ | XABCD-*E |
遇到NULL,抛出全部栈中元素 | 空 | XABCD-*E/+= |
2. 算法实现
#include <stdio.h>
#include <stdlib.h>
#include <err.h>
#include <string.h>
#include <ctype.h>
#define MAXSTACKSIZE 20
#define MAXSIZE 50
#define handle_error(msg) do{ perror(msg); exit(-1);}while(0);
typedef char TYPE;
typedef struct stack{
int stacksize;
int topofstack;
TYPE * arrary;
} STACK;
void destroy_stack();
TYPE pop();
TYPE top();
int push(TYPE );
STACK * creat_stack(int );
char * transfer_expression(char * );
int handle_experession(char *, char * );
STACK * ptr;
int main(void){
char infixexpression[MAXSIZE];
char * result;
ptr=creat_stack(MAXSTACKSIZE);
//获取表达式
if(fgets(infixexpression,MAXSIZE,stdin) == NULL)
errx(1, "gets error\n");
result=transfer_expression(infixexpression);
free(result);
destroy_stack(ptr);
}
char * transfer_expression(char * infixexpression){
char * ptr;
if((ptr=calloc(strlen(infixexpression), sizeof(char))) == NULL)
handle_error("malloc");
handle_experession(infixexpression,ptr);
printf("%s\n",ptr);
return ptr;
}
int handle_experession(char * infixexpression, char * result){
if(*infixexpression == '\n'||*infixexpression == '\0'){
for(;top() != -1;){
//debug
//printf("out %c\n",top());
*result++=pop();
}
return 0;
}
else if(isalnum(*infixexpression) != 0)
*result++=*infixexpression;
else
switch(*infixexpression){
case '*':
case '/':
for(;top() != -1;)
if(top() != '*' && top() != '/' || top() == '('){
push(*infixexpression);
//debug
//printf("in %c\n",top());
goto exit1;
}
else{
//debug
//printf("out %c\n",top());
*result++=pop();
}
push(*infixexpression);
//debug
//printf("in %c\n",top());
exit1:
break;
case '+':
case '-':
for(;top() != -1;)
if(top() == '('|| top() == '='){
push(*infixexpression);
//debug
//printf("in %c\n",top());
goto exit2;
}
else{
//printf("out %c\n",top());
*result++=pop();
}
push(*infixexpression);
//debug
//printf("in %c\n",top());
exit2:
break;
case '(':
push(*infixexpression);
//debug
//printf("in %c\n",top());
break;
case ')':
do{
printf("out %c\n",top());
*result++=pop();
}while(top() != '(');
//debug
//printf("pop %c\n",top());
pop();
break;
case '=':
for(;top() != -1;){
//debug
//printf("out %c\n",top());
*result++=pop();
}
push(*infixexpression);
//debug
//printf("in %c\n",top());
break;
}
return handle_experession(infixexpression+1,result);
}
STACK * creat_stack(int stacksize){
STACK * ptr;
if((ptr=malloc(sizeof(STACK))) == NULL)
handle_error("malloc");
ptr->stacksize=stacksize;
ptr->topofstack=-1;
if((ptr->arrary=malloc(stacksize*sizeof(TYPE))) == NULL)
handle_error("malloc");
return ptr;
}
int push(TYPE value){
if(ptr->topofstack== ptr->stacksize)
return -1;
(ptr->arrary)[++ptr->topofstack]=value;
return 0;
}
TYPE pop(){
if(ptr->topofstack== -1)
return -1;
return (ptr->arrary)[ptr->topofstack--];
}
TYPE top(){
if(ptr->topofstack== -1)
return -1;
return (ptr->arrary)[ptr->topofstack];
}
void destroy_stack(){
if(ptr != NULL){
free(ptr->arrary);
free(ptr);
}
}
结果:
[root@localhost ~]# ./3_3
x=a+b*(c-d)/e #这里是输入的中缀表达式
xabcd-*e/+=
[root@localhost ~]# ./3_3
4*5+3*(6*9)/5 #这里是输入的中缀表达式
45*369**5/+
[root@localhost ~]#
3. 回顾
笔者对 handle_experession
的实现,使用了递归的方式。最大的感触就是debug
的重要性,我们不能保证一次输入的代码就百分百能运行,总是因为一些小细节错误,导致结果与预期不同。所以必须强制自己编程时就考虑debug
点的设置。