栈的应用:基于栈的中缀表达式求值

本文非原创。

目的:输入一个中缀表达式,求解表达式的值。eg:20*(4.5-3)=

#define _CRT_SECURE_NO_WARNINGS  
#include<stdio.h>
#include <stdlib.h>
 
#define STACK_INIT_SIZE 100 //存储空间初始分配量 
#define STACKINCREMENT 10//存储空间增量 
typedef char ElemType;
typedef int Status;
 
typedef struct {    //存储运算符号*/+-()= 
	ElemType* base;
	ElemType* top;
	int stacksize;//当前分配的存储空间,以元素为单位。 
}SqStack, * SqStacklist; 
typedef struct {    //存储运算数 
	double* base;
	double* top;
	int stacksize;
}SqStack1, * SqStacklist1;

//栈的初始化 
SqStacklist InitStack() {            
	SqStacklist S;
	S = (SqStacklist)malloc(sizeof(SqStack));
	S->base = (ElemType*)malloc(STACK_INIT_SIZE * sizeof(ElemType));
	S->top = S->base;
	S->stacksize = STACK_INIT_SIZE;    
	return S;
}
SqStacklist1 InitStack1() {         
	SqStacklist1 S;
	S = (SqStacklist1)malloc(sizeof(SqStack1));
	S->base = (double*)malloc(STACK_INIT_SIZE * sizeof(double));
	S->top = S->base;
	S->stacksize = STACK_INIT_SIZE; 
	return S;
}
 
// e返回顶数值,并且删除栈顶数值
Status Pop1(SqStacklist1 S,double *e) {    
	if (S->top == S->base) return 0;
	*e = *--S->top;
}
Status Pop(SqStacklist S, ElemType* e) {   
	if (S->top == S->base) return 0;
	*e = *--S->top;
}
 

void DeleteTop(SqStacklist S) {              
	 S->top--;
}
 
//元素入栈 
void  Push(SqStacklist S, ElemType e) {       
	if (S->top - S->base >= S->stacksize) {
		S->base = (ElemType*)realloc(S->base, (S->stacksize + STACKINCREMENT) * sizeof(ElemType));  
		S->top = S->base + S->stacksize;
		S->stacksize += STACKINCREMENT;
	}
	*S->top++ = e;                    
} 
void  Push1(SqStacklist1 S, double e) {       
	if (S->top - S->base >= S->stacksize) {
		S->base = (double*)realloc(S->base, (S->stacksize + STACKINCREMENT) * sizeof(double)); 
		S->top = S->base + S->stacksize;
		S->stacksize += STACKINCREMENT;
	}
	*S->top++ = e;                    
}
 
//得到栈顶元素和pop区别是这里只能得到栈顶元素S->top - 1
ElemType GetTop(SqStacklist S) {          
	ElemType e = *(S->top - 1);
	return e;
}
double GetTop1(SqStacklist1 S) {          
	double e = *(S->top - 1);
	return e;
}
 
//判断两个符号的优先关系;从该链接可以看到解释:https://blog.youkuaiyun.com/yuluows/article/details/7657944 
char Precede(char theta1, char theta2)        
{
	int i, j;        
	char pre[][7] = {
		
					 {'>','>','<','<','<','>','>'},
					 {'>','>','<','<','<','>','>'},
					 {'>','>','>','>','<','>','>'},
					 {'>','>','>','>','<','>','>'},
					 {'<','<','<','<','<','=','0'},
					 {'>','>','>','>','0','>','>'},
					 {'<','<','<','<','<','0','='} };
 
	switch (theta1) {
	case '+': i = 0; break;
	case '-': i = 1; break;
	case '*': i = 2; break;
	case '/': i = 3; break;
	case '(': i = 4; break;
	case ')': i = 5; break;
	case '=': i = 6; break;
	}
 
	switch (theta2) {
	case '+': j = 0; break;
	case '-': j = 1; break;
	case '*': j = 2; break;
	case '/': j = 3; break;
	case '(': j = 4; break;
	case ')': j = 5; break;
	case '=': j = 6; break;
	}
	return(pre[i][j]);
}

//进行运算 
double Operate(double a, char theta, double b)   
{
	switch (theta) {
	case'+':return a + b;
	case'-':return a - b;
	case'*':return a * b;
	case'/':             //判断除数是否为0,若除数为零返回错误提示                       
		if (b != 0)
			return a / b;
		else
		{
			printf("分母不能为0!\n");
			exit(0);
		}
	}
}
//判断是否是运算符 
int In(char c)            
{
	switch (c) {
	case '+':
	case '-':
	case '*':
	case '/':
	case '(':
	case ')':
	case '=':
		return 1;
	default:
		return 0;
	}
}
 
//计算 
double Calculate(char str[]) {       
	SqStacklist S;
	SqStacklist1 S1;
	S = InitStack();       //存放符号
	S1 = InitStack1();      //存放数值
	double a, b,dtemp;
	ElemType theta;
	int i = 0;
	Push(S, '=');
 
	if (str[i] == '=') {    //若第一个字符为‘=’,则直接退出
		exit(0);
	}
 
	Push1(S1, 0);        //事先向S1中压入0,防止第一个数为负数而导致异常
 
	while (str[i] != '=' || GetTop(S) != '=') //表达式没有扫描完毕或S1的栈顶不为“=”
	{
 
		int m = 0;
		if (In(str[i])) //判断是否为操作符
		{
			switch (Precede(GetTop(S), str[i]))//比较str[i]与S1栈顶元素的优先级
			{
			case'<'://栈顶元素的优先权较低 
				Push(S, str[i++]);
				break;
  
			case'>'://退栈并将结果入栈 
				Pop(S, &theta);
				Pop1(S1, &b);
				Pop1(S1, &a);
				Push1(S1, Operate(a, theta, b));
				break;        //i没有++,意味着继续读这个符号,即str[i]没变
 
			case'=':
				DeleteTop(S);   //脱括号并接受下一字符; 即栈顶为‘(',str[i]为')',此时将栈顶元素删除即可
				i++;
				break;
			}
		}
 
	else if ((str[i] >= '0' && str[i] <= '9') || str[i] == '.')       //判断是否为数字
		{
			char num[100] = {};
			int j = 0;
			while ((str[i] >= '0' && str[i] <= '9') || str[i] == '.') {   //生成数
 
				num[j++] = str[i];
				if ((str[i + 1] >= '0' && str[i + 1] <= '9') || str[i + 1] == '.') i++;
				else break;
			}
			dtemp = atof(num);
			Push1(S1, dtemp);
			i++;
		}
		else
		{
			printf("输入非法字符\n");   //返回错误提示
			exit(0);          
		}
	}
	return(GetTop1(S1));      //最后返回操作数栈顶为运算结果
}

int main() {
	while (1) {
		char str[100];           //存储表达式
		printf("请输入表达式:\n");
		scanf("%s", str);
		double result = Calculate(str);
		printf("结果是:%.2f\n\n", result);
	}
	return 0;
}

同学希望帮到你。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值