中缀表达式就是我们平时所看到的一般计算表达式,如:
①最简单的: 1 + 1
②稍微复杂一点的: 8 – ( 3 + 2 * 6 ) / 5 + 4
而后缀表达式(也被称为逆波兰式)则是将运算符放在了最后,两个操作数放在前面,以及不需要括号表示运算的优先级, 如:
①1 + 1 对应的就是 1 1 +
②8 – ( 3 + 2 * 6 ) / 5 + 4 对应的就是 8 3 2 6 * + 5 / – 4 +
详细逆波兰式的定义请参考百度百科
http://baike.baidu.com/link?url=7RYiuxHeWH7ikiVkP6s7RxwBrowWemzp_yL9MkqsBMd0Q3KAFB_35XexPBsq6g-ZvRoHE6MpQIaCzNbyMnI6Qq
OJ题可参考
http://codevs.cn/problem/2471/
现在当我们输入一个中缀表达式(不能有负数输入)的时候,我们通过两个栈来得到后缀表达式,这里我采用链表来实现栈,当然你也可以使用数组(更节省空间)。
typedef struct Node {
char element; //储存操作数或者运算符
struct Node *prev;
struct Node *next;
}Node;
typedef struct {
Node *top;
Node *base;
}Stack;
//以及栈的一些基本操作
//初始化栈,栈底设头结点,并以'#'为栈底标志
Stack *IntiStack(){
Stack *result = (Stack *)malloc(sizeof(Stack));
Node *headNode = (Node *)malloc(sizeof(Node));
headNode->prev = NULL;
headNode->next = NULL;
headNode->element = '#';
result->top = headNode;
result->base = headNode;
return result;
}
//将一个操作数或者运算符推进栈中
void Push(Stack *result, char element){
Node *newNode = (Node *)malloc(sizeof(Node));
newNode->element = element;
newNode->prev = result->top;
newNode->next = NULL;
result->top->next = newNode;
result->top = newNode;
}
//获得栈中顶元素的值
char getTop(Stack *result){
return result->top->element;
}
//将栈中顶元素的值弹出,除非栈为空
char Pop(Stack *result){
char temp;
if(result->top != result->base){
temp = result->top->element;
result->top = result->top->prev;
result->top->next = NULL;
return temp;
}
return '#';
}
首先第一个栈temp是一个临时栈,负责储存运算符,并且该栈的头元素优先级最高(即从底到头优先级递增), 第二个栈result是结果栈, 从底到头储存了一个完整的后缀表达式。
中缀表达式转换为后缀表达式最为重要的就是当我碰到一个操作数或者运算符的时候应该怎么处理, 也就是优先级的确认。
①遇到操作数的时候直接推进result
②遇到运算符的时候需要比较该运算符与temp栈头元素的运算符的优先级,如果该运算符优先级高于(不包括等于)则将运算符推进temp, 否则弹出temp栈的头元素直到头元素的优先级低于该运算符,最后将该运算符推进temp中。
③当然有特殊情况,也就是遇到左括号“(”的时候直接推进temp, 当其他运算符与左括号比较优先级的时候可认为左括号的优先级最低。遇到右括号的时候,不断弹出栈的头元素直到遇到左括号,左括号弹出后不入result(后缀表达式不需要括号)
④接下来我们详细讨论每种情况:
“+”:优先级是最低的,几乎所有运算符都要弹出(包括加号自身),除了左括号。
“-”:与加号优先级相同,同上。
“*”:优先级稍高,只有遇到乘号,除号,以及幂号的时候才需要弹出。
“/”:与乘号优先级相同,同上。
“^”:优先级最高