数据结构9————栈的应用3-后缀表达式

数据结构9————栈的应用3-后缀表达式

一.前言

1. 中缀表达式是什么

是一个通用的算术或逻辑公式表示方法, 操作符是以中缀形式处于操作数的中间(例:3 + 4),中缀表达式是人们常用的算术表示方法。

2. 后缀表达式(逆波兰表达式)是什么

后缀表达式,指的是不包含括号,运算符放在两个运算对象的后面,所有的计算按运算符出现的顺序,严格从左向右进行(不再考虑运算符的优先规则)。比如 3 4 +(即中缀3+4的意思)

3. 本篇博文的主要内容
  • 中缀表达式转后缀表达式
  • 后缀表达式的计算
4. 其他
  • 和我之前其他博文一样,所以代码只贴核心代码,其他代码,如栈的运算相关的代码并没有贴出来。
  • 如果想看完整代码。可以去文末的git地址下载,相关代码。

二.中缀表达式转后缀表达式

1.思路
  • 从左到右遍历中缀表达式的每个数字和符号,若是数字就将计数(数字的长度);
  • 若是符号,先将之前记录的数字存放到结果数组中,并判断其与栈顶符号的优先级,是右括号或优先级低于或等于栈顶符号(乘除优先加减)则栈顶元素依次出找并存放到结果数组。
  • 当栈顶符号优先级高于当前符号或者空栈时,将当前符号入栈(当前符号不为‘)’)。
  • 当中缀表达式遍历完后,将最后一个数字存放到结果数组中,并将符号栈里的所有符号依次出栈,并存入结果数组中。
  • 输出结果数组中的所有元素。
2.代码(完整代码见文末链接)

结构体的构建

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXSIZE 40
#define TRUE 1
#define FALSE 0 
typedef struct//栈内元素,存符号或者数字
{
	char string[10]; 
} Elemtype;
typedef struct
{
	Elemtype data[MAXSIZE]; 
	int top; 
}SeqStack; 

优先级

int Priority(Elemtype e1){
	switch(e1.string[0]){
		case '+':
			return 1;
		case '-':
			return 1;
		case '*':
			return 2;
		case '/':
			return 2;
		case '(':
			return 0;
		case ')':
			return 0;
	}
}

核心代码

SeqStack *sign;//符号 
Elemtype result[50];//结果
int result_top=0;
int Convert(char str[]) {
	Elemtype e1,e2,e3; //e1,表达式截取的数字。e2,表达式截取的符号(待入栈)。e3符号栈栈顶符号 
	int i,j,count=0; //count计算数字的长度 
	
	for(i=0;str[i];i++){
		if(str[i]>='0'&&str[i]<='9'){ //如果是数字
			e1.string[count]=str[i];
			count++; 
		}  
		else{
			if(count>0){ 
				e1.string[count]=0;
				result[result_top]=e1;//数字存入结果数组中 
				result_top++; 
			}
			
			e2.string[0]=str[i];
			e2.string[1]=0;
			
			if(str[i]=='('){      //左括号直接入栈 
				Push(sign,e2); 
			}else if(str[i]=='+'||str[i]=='-'||str[i]=='*'||str[i]=='/'||str[i]==')'){ 				
				
				GetTop(sign,&e3);
				//和栈顶元素比较,如果比栈顶元素优先级低/相等,出栈栈顶
				//直到栈空,或着当前符号比栈顶元素优先级高,或者碰到'(' 
				while(StackEmpty(sign)==0&&Priority(e2)<=Priority(e3)&&e3.string[0]!='('){  
					Pop(sign,&e3);//出栈 
					result[result_top]=e3;//存入结果数组中 
					result_top++; 
					GetTop(sign,&e3);//取出下一个栈顶元素 
				}
				if(e2.string[0]!=')'){//如果当前符号不是')',将符号入栈 
					Push(sign,e2);	
				}else{            //如果是')',出栈栈顶的'('符号 
					Pop(sign,&e3);
				}	
			}else {
				printf("错误!");
				return;
			} 
		 	count=0;//数字的计数器重置 
		}
	}
	//结束时
	e1.string[count]=0;
	result[result_top]=e1;//存入结果数组中 
	result_top++;  
	while(!StackEmpty(sign)){
		Pop(sign,&e3);
		result[result_top]=e3;//存入结果数组中 
		result_top++;  
	}
	
	for(i=0;i<result_top;i++){
		printf("%s ",result[i].string);
	}
	printf("\n");
}
int main(void){
	sign=InitStack(); 
	char str[100]="9+(3-1)*3+10/2";
	//scanf("%s",str); 
	Convert(str);
}

三.后缀表达式的运算

1.思路
  • 从左到右遍历后缀表达式(结果数组)的每个数字和符号,遇到是数字就进栈(数字栈),遇到是符号,就将处于栈(数字栈)顶两个数字出栈,进行运算,运算结果进栈(数字栈),一直到最后获得结果
  • 输出数字栈里的数字(计算正确的话,栈内只有一个数组)。
2.其他
  • 在完整代码版中,后缀表达式来源于前一个代码,所以后缀表达式的来源于结果数组。
  • 结合这个代码和上面的代码可以直接计算算术表达式的值
3.代码(完整代码见文末链接)

结构体的构建同上

数字和字符串之间的转换

int strnum(Elemtype e1){
	int sum=0,i;
	for(i=0;e1.string[i];i++){
		sum=sum*10+e1.string[i]-'0';
	}
	return sum;
} 
Elemtype numstr(int sum){
	Elemtype e;
	char c;
	int i;
	for(i=0;sum;i++){
		e.string[i]=sum%10+'0';
		sum=sum/10;
	}
	e.string[i]=0;
	for(i=0;i<strlen(e.string)/2;i++){
		c=e.string[i];
		e.string[i]=e.string[strlen(e.string)/2-i];
		e.string[strlen(e.string)/2-i]=c;				
	}
	return e;
} 

核心代码

SeqStack *num;//数字栈 
Elemtype result[50];//结果
void Calculate(){
	int sum;
	Elemtype e1,e2;
	int i;
	for(i=0;i<result_top+1;i++){ //是数字就入栈 
	
		if(result[i].string[0]>='0'&&result[i].string[0]<='9'){
			Push(num,result[i]);
		}else{  //是符号就出栈两个栈顶元素并运算 ,然后入栈 
			Pop(num,&e1);
			Pop(num,&e2);
			switch(result[i].string[0]){
				case '+':
					sum = strnum(e2) + strnum(e1);
					break;
				case '-':
					sum = strnum(e2) - strnum(e1);
					break;
				case '*':
					sum = strnum(e2) * strnum(e1);
					break;
				case '/':
					sum = strnum(e2) / strnum(e1);
					break;
			}
			e1=numstr(sum);
			Push(num,e1);	
		}
	}
	printf("%s\n",num->data[0].string);
}
int main(void){
	sign=InitStack();//创建栈 
	num=InitStack();
	
	char str[100]="9+(3-1)*4+10/2";
	//char str[100];
	//scanf("%s",str); 
	Convert(str);
	Calculate(result); 
}

四.其他可进行的优化

  • 可以进行小数优化
  • 引入负号
  • 可以一次遍历直接将算术表达式的结果计算出来

五.源代码

text6中

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值