王道408——資料結構-棧-逆波蘭式(字尾表示式)求值
阿新 • • 發佈:2020-12-21
技術標籤:資料結構
日常生活中我們常常可以見到各種各樣的表示式
例如這樣:
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;
}
————考研狗日常筆記歡迎各路神仙斧正