Bootstrap

王道408——数据结构-栈-逆波兰式(后缀表达式)求值

日常生活中我们常常可以见到各种各样的表达式
例如这样:

1+2*(3+5)-4=?

这样:

3*5*(2*(1+3))-4=?

如果我们需要使用程序来解决这样的问题那么我们首先需要考虑的是如何区分各种符号的优先级?如何使括号内的数优先计算?

为了解决这个问题波兰数学家扬·武卡谢维奇1920年引入的数学表达式方式,在逆波兰记法中,所有操作符置于操作数的后面,因此也被称为后缀表示法。逆波兰记法不需要括号来标识操作符的优先级。

HOW(如何将中缀表达式转换成后缀表达式)?

实现这一操作就用到了栈这种数据结构,我们扫描字符串,遇到数字直接插入到后缀表达式中。
如果遇到符号:
1)判断栈内是否为空如果栈内为空直接压入栈中
2)如果栈不为空我们需要判断栈顶符号的优先级是否大于当前符号优先级,如果大于当前符号优先级则弹出栈,将符号放入到中缀表达式中,否则把当前符号压入栈中。
到字符串结尾后,将栈中元素依次弹出栈放入中缀表达式即可。

后缀表达式如何求值

我们遍历后缀表达式,遇见数字则压入栈中,遇到符号则弹出两个数字进行计算并将结果压入栈中。这里需要注意计算时两个运算数的顺序

code

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

//栈结构体
typedef struct LinkList{
	void *data;
	struct LinkList *next;
}stack;

//初始化栈操作
stack *initStack(){
	stack *s = (stack *)malloc(sizeof(stack));
	if(s == NULL){
		printf("%s: apply memory error\n", __func__);
		exit(1);
	}
	s->next = NULL;
	return s;
}

//压栈操作
void pushStack(stack *s, void *data, int size){
	stack *tmp = (stack *)malloc(sizeof(stack));
	if(tmp == NULL){
		printf("%s: apply memory error\n", __func__);
		exit(1);
	}
	tmp->data = (void *)malloc(size);
	memcpy(tmp->data, data, size); //泛型,拷贝内存
	tmp->next = s->next;
	s->next = tmp;
}

//出栈操作
void popStack(stack *s){
	if(s->next == NULL){
		printf("%s: null\n", __func__);
		exit(1);
	}
	stack *tmp = s->next;
	s->next = tmp->next;
	free(tmp);
}

//获取栈顶元素
void getTopStack(stack *s, void *ans, int size){
	if(s->next == NULL){
		printf("%s: null\n", __func__);
		exit(1);
	}
	memcpy(ans, s->next->data, size);
}

//判断栈是否为空
int empty(stack *s){
	if(s->next == NULL){
		return 1;
	}
	else{
		return 0;
	}
}

//获取当前运算符的优先级
int judge(char s){
	if(s == '+' || s == '-'){
		return 1;
	}
	else if(s == '*' || s == '/'){
		return 2;
	}
	else if(s == ')' || s == '('){
		return 0;
	}
}

//释放栈操作
void freeStack(stack *s){
	stack *tmp = NULL;
	while(s != NULL){
		tmp = s;
		s = s->next;
		free(tmp);
	}
}

//中缀表达式转后缀表达式
void trans(char *expression, char *rpn){
	stack *s = initStack();
	int i = 0;
	while(*expression){
		if((*expression) >= '0' && (*expression) <= '9'){
			rpn[i++] = *expression;
		}
		else{
			if(empty(s)){
				pushStack(s, expression, sizeof(char));
			}
			else{
				if(*expression == '('){
					pushStack(s, expression, sizeof(char));
					//continue;
				}
				else if(*expression == ')'){
					char c;
					getTopStack(s, &c, sizeof(char));
					while(c != '('){
						rpn[i++] = c;
						popStack(s);
						getTopStack(s, &c, sizeof(char));
					}
					popStack(s);
				}
				else{
					char c;
					getTopStack(s, &c, sizeof(char));
					if(judge(c) < judge(*expression)){
						pushStack(s, expression, sizeof(char));
					}
					else{
						rpn[i++] = c;
						popStack(s);
						pushStack(s, expression, sizeof(char));
					}
				}
			}
		}
		expression++;
	}
	while(!empty(s)){
		char c;
		getTopStack(s, &c, sizeof(char));
		rpn[i++] = c;
		popStack(s);
	}
}

//计算
int cal(int a, int b, char c){
	int m = a;
	int n = b;
	int ans = 0;
	switch(c){
		case '+':
			ans = m + n;
			break;
		case '-':
			ans = m - n;
			break;
		case '*':
			ans = m * n;
			break;
		case '/':
			ans = m / n;
			break;
		default:
			break;
	}
	return ans;
}

//后缀表达式求值
int evaluation(char *rpn){
	stack *s = initStack();
	int ans = 0;
	while(*rpn){
		if(*rpn >= '0' && *rpn <= '9'){
			int tmp = *rpn - '0';
			pushStack(s, &tmp, sizeof(int));
		}
		else{
			int m, n;
			getTopStack(s, &n, sizeof(int));
			popStack(s);
			getTopStack(s, &m, sizeof(int));
			popStack(s);
			ans = cal(m, n, *rpn);
			pushStack(s, &ans, sizeof(int));
		}
		rpn++;
	}
	return ans;
}

int main(){
	int i, len, m, n, tmp1, tmp2, ans;
	char expression[256];//中缀表达式
	char rpn[256];//后缀表达式
	scanf("%s", expression);
	trans(expression, rpn);
	printf("%s\n", rpn);
	printf("%d\n", evaluation(rpn));
	return 0;
}

————考研狗日常笔记欢迎各路神仙斧正

;