中缀表达式转后缀表达式
所谓中缀,即常见的那种表达式,如
后缀表达式则是计算机内部实际的计算方式,如
转换方法
对于”8+(3-1)*5”
先创建一个用来保存符号的栈stack
从左开始遍历每个字符:
对于数字:
直接输出
对于符号:
遇到左括号,进栈
遇到运算符号(+-*/),与栈顶的符号进行优先级比较,如果栈顶的优先级低,符号进栈(默认栈顶若是左括号,左括号优先级最低)。若栈顶符号优先级不低,先将栈顶符号弹出并输出,之后再让当前进栈。
遇到右括号,将栈顶符号弹出并输出,直到匹配左括号。(之后也把左括号弹掉,但不输出到屏幕)
当字符串遍历完毕,把栈中所有符号弹出就结束。
计算后缀表达式
表达式:831-5* +
从左开始遍历每个字符:
对于数字:
直接入栈
对于符号:
从栈中弹出一个右操作数
再从栈中弹出一个左操作数
根据符号进行运算(左 符号 右 = 结果)
将结果压入栈中
当遍历结束,栈中的唯一数字为计算结果。
(注:a+b,a为左操作数,b为右操作数)
实验结果
代码示例
#include<cstdlib>
#include<cstdio>
#include<cstring>
using namespace std;
//c++中纯c语法
//---------------------------part1,自定义链式栈的实现
//用链表实现的后入先出的栈
//链表节点
typedef struct LINKNODE
{
//注意是指针
struct LINKNODE* next;
}LinkNode;
//栈,每个节点都是一个链表节点
typedef struct STACK
{
LinkNode head;
int size;
}Stack;
//自定义一个数据类型,且第一个元素放节点指针,也就是Person* 和 LinkNode*可以无缝互转
typedef struct PERSON
{
LinkNode *node;
int age;
char name[64];
}Person;
//创建一个空栈
Stack* init()
{
Stack* stack = (Stack*)malloc(sizeof(Stack));
stack->size = 0;
stack->head.next = NULL;
}
//push,栈底在最后面栈顶和head连在一起
void push(Stack* stack,LinkNode* data)
{
if(stack==NULL || data == NULL)
{
return;
}
data->next = stack->head.next;
stack->head.next = data;
//每次记得size+1啊
stack->size ++;
}
//获得栈顶
LinkNode* top(Stack* stack)
{
if(stack==NULL || stack->size == 0)
{
return NULL;
}
return stack->head.next;
}
//出栈
void pop(Stack* stack)
{
if(stack==NULL || stack->size ==0)
{
return;
}
stack->head.next = stack->head.next->next;
//这里之前忘记--了
stack->size --;
}
//栈是否为空
int isEmpty(Stack* stack)
{
//注意了,是0返回1
if(stack->size == 0)
{
return 1;
}
return 0;
}
//测试栈
void test()
{
Stack* stack = init();
Person p1;
Person p2;
Person p3;
Person p4;
Person p5;
printf("test\n");
strcpy(p1.name,"aaa");
strcpy(p2.name,"bbb");
strcpy(p3.name,"ccc");
strcpy(p4.name,"ddd");
strcpy(p5.name,"eee");
p1.age = 1;
p2.age = 2;
p3.age = 3;
p4.age = 4;
p5.age = 5;
push(stack,(LinkNode*)&p1);
push(stack,(LinkNode*)&p2);
push(stack,(LinkNode*)&p3);
push(stack,(LinkNode*)&p4);
push(stack,(LinkNode*)&p5);
//后入先出
for(int i = 0;i<5;i++)
{
printf("%d:%s\n",((Person*)top(stack))->age,((Person*)top(stack))->name);
pop(stack);
}
}
//---------------------------part2,中缀表达式转后缀
//一个用来存放临时的运算符,包括括号,+-*/
typedef struct MYDATA
{
LinkNode* node;
char c;
}MyData;
//判断是左括号
int isLeft(char c)
{
if(c=='(')
return 1;
return 0;
}
//判断右括号
int isRight(char c)
{
if(c==')')
return 1;
return 0;
}
//是否是数字
int isDigital(char c)
{
if(c>='0' && c<='9')
{
return 1;
}
return 0;
}
//看看是否是运算符
int isOperator(char c)
{
if(c=='+' ||c=='-' ||c=='*' ||c=='/')
{
return 1;
}
return 0;
}
//看看栈顶符号的优先级
int getPriority(char c)
{
if(c=='+' ||c=='-')
{
return 1;
}
if(c=='*' ||c=='/')
{
return 2;
}
}
//自己弄的打印
void print(char c)
{
printf("%c",c);
}
//快速把一个字符变成栈顶
LinkNode* operatorNode(char c)
{
MyData* data = (MyData*)malloc(sizeof(MyData));
data->c = c;
return (LinkNode*)data;
}
//提取栈顶元素中的字符
char extractTopChar(Stack* stack)
{
return ((MyData*)top(stack))->c;
}
void test2()
{
//char* str = "(8+(((3-1))*5))";//answer 831-5*+
char* str = "1+(3*2+1*3+(5*1))";
char* p = str;
Stack* stack = init();
printf("中缀表达式%s转成后缀表达式是:",str);
while(*p!='\0')
{
if(isDigital(*p))
{
//数字直接打印
print(*p);
}
if(isLeft(*p))
{
//遇到左括号直接入栈
push(stack,operatorNode(*p));
}
if(isRight(*p))
{
//printf("test\n");
//如果是右括号,直接弹出所有栈顶元素,直到遇到左括号
while(extractTopChar(stack)!='(')
{
print(extractTopChar(stack));
pop(stack);
}
//把剩下的左括号也弹掉
pop(stack);
}
if(isOperator(*p))
{
//原本的栈是空的或者是左括号直接入栈
if(isEmpty(stack) || isLeft(extractTopChar(stack)))
{
push(stack,operatorNode(*p));
}
//还要看看栈顶是不是加减符号,不然没什么好比的
else if(isOperator(extractTopChar(stack)))
{
//若栈顶的优先级较低,新来的符号入栈
if(getPriority(*p)>getPriority(extractTopChar(stack)))
{
push(stack,operatorNode(*p));
}else
{
//否则要先出栈输出再入栈
print(extractTopChar(stack));
pop(stack);
//入栈
push(stack,operatorNode(*p));
}
}
}
p++;
}
//把栈剩余的内容都打印出来
while(!isEmpty(stack))
{
print(extractTopChar(stack));
pop(stack);
}
printf("\n");
}
//---------------------------part3,求解后缀表达式的值
//简要原理,数字就压栈,遇到运算符,就出栈顶当右值,再出一次栈顶当左值
//计算后再放回去,一直到把表达式字符串遍历完,栈中剩余的元素就是最终的结果
int calc(char oper,int right,int left)
{
//int right = rightVal - '0';
//int left = leftVal - '0';
switch(oper)
{
case '+':return left+right;
case '-':return left-right;
case '*':return left*right;
case '/':return right==0?-10086:(left/right);
}
}
//栈的数据节点稍微要改下,不是存char了,是int
typedef struct DATA
{
LinkNode* node;
int val;
}Data;
LinkNode* dataNode(int val)
{
Data* data = (Data*)malloc(sizeof(Data));
data->val = val;
return (LinkNode*)data;
}
int extractTopInt(Stack* stack)
{
return ((Data*)(top(stack)))->val;
}
void test3()
{
//char* str = "831-5*+";
char* str = "132*13*51*+++";
//主要是拷贝一份,避免在原有数据上改
char* p = str;
//栈的主力军变成int,part2是运算符
Stack* stack = init();
while(*p!='\0')
{
if(isDigital(*p))
{
int val = *p - '0';
push(stack,dataNode(val));
}
if(isOperator(*p))
{
int rightVal = extractTopInt(stack);
pop(stack);
int leftVal = extractTopInt(stack);
pop(stack);
push(stack,dataNode(calc(*p,rightVal,leftVal)));
}
p++;
}
if(!isEmpty(stack))
{
printf("后缀表达式%s的计算结果是:%d\n",str,extractTopInt(stack));
}
}
int main()
{
//test();//测试栈
test2();//中缀变后缀
test3();
return 0;
}