编译器中的表达式求值问题

1 问题描述

表达式求值是比较常见的问题,通常在编写程序时,直接写出表达式让编译器去处理,却很少关心编译器是如何对表达式求值。

整数加减乘除四则运算的规则如下:

1)先乘除,后加减;

2)同一优先级,从左算到右;

3) 先括号内,后括号外。

按中缀形式输入一个四则运算的表达式,利用算符优先关系把其转换为后缀表达式输出,并求表达式的值。假设输入的表达式中的操作数都是1位整数。

一个简单合法的中缀表达式可由“(”,“)”,“0”~“9”,“+”,“-”,“*”,“/”(“/”表示整数除法)构成。

  1. 输入要求

输入数据可以有多组,每一组测试数据为带小括号的四则运算中缀表达式。

  1. 输出要求

对于每组测试数据输出两行,第一行四则运算表达式的后缀表达式(每个数字或者操作符之间输出空格,最后一个元素后没有空格),第二行运算结果。 除法操作为整除,比如6/4=1。

程序如下

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

#define FALSE 0
#define TRUE 1
#define STACKSIZE 20  //堆栈容量,可根据需要进行调整
#define ITEMSIZE 20   //表达式中元素的最大长度,可根据需要进行调整
#define EXPSIZE 200   //表达式最大长度

typedef char ElemType;
typedef int BOOL;
/*用于前缀转后缀表达式的栈空间(操作符入栈)*/
typedef struct stack
{
	int top;
	int maxSize;
	ElemType *element;
}Stack;
/*用于后缀表达式计算的栈空间(操作数入栈)*/
typedef struct stack_
{
	int top;
	int maxSize;
	double *element;
}Stack_;

void Create(Stack *S,int mSize)
{
	S->maxSize = mSize;
	S->element = (ElemType*)malloc(sizeof(ElemType)*mSize);
	S->top = -1;
}
void Create_(Stack_ *S, int mSize)
{
	S->maxSize = mSize;
	S->element = (double*)malloc(sizeof(double)*mSize);
	S->top = -1;
}

BOOL IsFull(Stack *S)
{
	return S->top == S->maxSize - 1;
}
BOOL IsFull_(Stack_ *S)
{
	return S->top == S->maxSize - 1;
}

BOOL Push(Stack *S, ElemType x)
{
	if (IsFull(S))
		return FALSE;
	S->top++;
	S->element[S->top] = x;
	return TRUE;
}
BOOL Push_(Stack_ *S, double x)
{
	if (IsFull(S))
		return FALSE;
	S->top++;
	S->element[S->top] = x;
	return TRUE;
}

BOOL IsEmpty(Stack *S)
{
	return S->top == -1;
}
BOOL IsEmpty_(Stack_ *S)
{
	return S->top == -1;
}

BOOL Top(Stack *S, ElemType *x)
{
	if (IsEmpty(S))  return FALSE;
	*x = S->element[S->top];
	return TRUE;
}
BOOL Top_(Stack_ *S, double *x)
{
	if (IsEmpty(S))  return FALSE;
	*x = S->element[S->top];
	return TRUE;
}

BOOL Pop(Stack *S)
{
	if (IsEmpty(S))  return FALSE;
	S->top--;
	return TRUE;
}
BOOL Pop_(Stack_ *S)
{
	if (IsEmpty_(S))  return FALSE;
	S->top--;
	return TRUE;
}

void Output(Stack *S)
{
	int i ;
	printf("当前栈空间:");
	for (i = 0; i <= S->top; i++)
	{
		printf("%c ", S->element[i]);
	}
	printf("\n");
}

void Destroy(Stack *S)
{
	S->maxSize = 0;
	free(S->element);
	S->top = -1;
}
void Destroy_(Stack_ *S)
{
	S->maxSize = 0;
	free(S->element);
	S->top = -1;
}

BOOL IsLegal(char *postfix)
{
	int i;
	char c;
	for (i = 0; i < strlen(postfix); i++)
	{
		c = postfix[i];
		if (!((c >= '0' && c <= '9') || c == '+' || c == '-' || c == '*' || c == '/' || c == ' ' || c == '(' || c == ')'))
			return FALSE;
	}
	return TRUE;
}

/*提取元素,返回元素的类型*/
int GetItem(char *postfix, int *curPos, char *item)
{
	int i = 0, k = *curPos, flag;
	if (postfix[k] == '.')
		flag = -1;
	else if (postfix[k] >= '0'&& postfix[k] <= '9')
	{
		while ((postfix[k] >= '0'&&postfix[k] <= '9') || postfix[k] == '.')
			item[i++] = postfix[k++];
		item[i] = '\0';
		flag = 0;
	}
	else
	{
		item[0] = postfix[k++];
		item[1] = '\0';
		flag = 1;
	}
	/*跳过当前元素的空格,下一次取元素起始位置是非空字符*/
	while (postfix[k] == ' ')
		k++;
	*curPos = k;
	return flag;
}
/*获取栈外优先级*/
int ICP(char c)
{
	if (c == '#')
		return 0;
	else if (c == '(')
		return 7;
	else if (c == '*' || c == '/')
		return 4;
	else if (c == '+' || c == '-')
		return 2;
	else if (c == ')')
		return 1;
	else 
	{
		printf("后缀表达式不支持此操作符%c!\n", c);
		exit(0);
	}
}
/*获取栈内优先级*/
int ISP(char c)
{
	if (c == '#')
		return 0;
	else if (c == '(')
		return 1;
	else if (c == '*' || c == '/')
		return 5;
	else if (c == '+' || c == '-')
		return 3;
	else if (c == ')')
		return 7;
	else
	{
		printf("后缀表达式不支持此操作符%c!\n", c);
		exit(0);
	}
}

/*前缀转后缀表达式*/
void InfixToPostfix(char *infix, char *postfix)
{
	Stack S;
	char item[ITEMSIZE];//存储表达式中的各个元素
	int flag = -1,      //代表操作符类型
		curPos = 0, 
		k = 0, i;
	char ch,                       //存放操作符元素
		curOP;                     //存储中缀表达式存储在数组中的操作符元素
	while (infix[curPos] == ' ')
		curPos++;                  //过滤空格
	Create(&S, STACKSIZE);
	Push(&S, '#');

	while (curPos < strlen(infix))
	{
		flag = GetItem(infix, &curPos, item);//获取元素即元素类型(返回值为1代表运算符,返回值0代表操作数,-1代表异常)
		//printf("item:%s\t",item);
		/*flag==-1,此时异常*/
		if (flag == -1)
		{
			printf("异常:中缀表达式不合法!\n");
			exit(0);
		}
	    /*flag==1,此时为运算符*/
		else if (flag == 1)
		{
			curOP = item[0];
			if (curOP == ')')
			{
				Top(&S, &ch); 
				Pop(&S); 
				//Output(&S);
				//遇到右括号则连续出栈直至遇到左括号
				while (ch!='(')
				{
					postfix[k++] = ch;
					postfix[k++] = ' ';
					Top(&S, &ch);
					Pop(&S);
					//Output(&S);
					
					postfix[k] = '\0';
					//printf("进行括号内的运算符处理时,当前后缀表达式为%s \n", postfix);
				}
				//Pop(&S);
			}
			else if (curOP == '(')
			{
				Push(&S, curOP);
				//Output(&S);

				//postfix[k] = '\0';
				//printf("进行括号内的运算符处理时,当前后缀表达式为%s \n", postfix);
			}
			else
			{
				//ch存放的是栈顶元素,curOP存放的是栈外当前操作符
				Top(&S, &ch);

				//如果栈外优先级 >= 栈内优先级
				if (ICP(curOP) >= ISP(ch))
				{
					Push(&S, curOP);
					//Output(&S);
				}
				else
				{
					//如果栈内优先级 > 栈外优先级,连续出栈直到栈内 > 栈外
					while (ICP(curOP) < ISP(ch))
					{
						postfix[k++] = ch;
						postfix[k++] = ' ';
						Pop(&S);
						Top(&S, &ch);
						//Output(&S);
					}
					Push(&S, curOP);
				}
			}

			//postfix[k] = '\0';
			//printf("此时的后缀表达式为%s \n", postfix);
		}
		/*flag==0,此时为操作数*/
		else 
		{
			for (i = 0; i < strlen(item); i++, k++)
			{
				postfix[k] = item[i];
				postfix[++k] = ' ';                                                          
			}

			//postfix[k] = '\0';
			//printf("此时的后缀表达式为%s \n", postfix);
		}

	}
	Top(&S, &ch);
	Pop(&S);
	while (ch != '#') 
	{
		postfix[k++] = ch;
		postfix[k++] = ' ';
		Top(&S, &ch);
		Pop(&S);
		postfix[k] = '\0';

		//printf("遍历完毕,栈非空情况下,此时的后缀表达式为%s \n", postfix);
		//Output(&S);
	}
	postfix[--k] = '\0';
}

/*提取栈空间的两个值让并将计算结果入栈*/
void DoOperator(Stack_ *S, char oper)
{
	double oper1, oper2;
	if (!Top_(S, &oper1))
	{
		printf("异常:后缀表达式格式出错,存在多余的操作符!\n");
		exit(0);
	}
	Pop_(S);
	if (!Top_(S, &oper2))
	{
		printf("异常:后缀表达式格式出错,存在多余的操作符!\n");
		exit(0);
	}
	Pop_(S);
	//printf("当前运算:%.2f%c%.2f\n", oper1, oper, oper2);
	switch (oper)
	{
	case '+':
		Push_(S, oper1 + oper2);
		break;
	case '-':
		Push_(S, oper2 - oper1);
		break;
	case '*':
		Push_(S, oper2 * oper1);
		break;
	case '/':
		if (fabs(oper1) < 1e-6)
		{
			printf("异常:除数不可为0!\n");
			exit(0);
		}
		else Push_(S, oper2/ oper1);
		break;
	case '^':
		Push_(S, pow(oper2 , oper1));
		break;
	}
}

double Caculating(char *postfix)
{
	Stack_ S;
	char item[ITEMSIZE];
	double data;
	int flag = -1;
	int curPos = 0;
	while (postfix[curPos] == ' ')
		curPos++;
	Create_(&S, STACKSIZE);
	while (curPos < strlen(postfix))
	{
		flag = GetItem(postfix, &curPos, item);
		
		if (flag == -1)
		{
			printf("异常:后缀表达式不合法!\n");
			exit(0);
		}
		else if (flag == 1)
		{
			//printf("当前运算符%c\n", item[0]);
			switch (item[0])
			{
			case '+':
			case '-':
			case '*':
			case '/':
			case '^':
				DoOperator(&S, item[0]);
				break;
			}
		}
		else
		{
			data = atof(item);
			//printf("当前数据为%f\n", data);
			Push_(&S, data);
		}
	}
	if (S.top == 0)
		Top_(&S, &data);
	else
	{
		printf("异常:后缀表达式格式出错,存在多余操作数!\n");
		exit(0);
	}
	Destroy_(&S);
	return data;
}

int main()
{
	/*
	    可直接复制的测试案例:
			(7+8)*9          7 8 + 9 *                135
			8-(3+2*6)/5+4    8 3 2 6 * + 5 / - 4 +    9
	*/
	char infix[EXPSIZE];
	char postfix[EXPSIZE];
	printf("请输入中缀表达式:\n");
	gets(infix);
	if (!IsLegal(infix))                    
	{
		printf("异常:中缀表达书存在非法字符!\n");
		return 0;
	}
	InfixToPostfix(infix, postfix);
	printf("\n对应后缀表达式为%s \n", postfix);
	printf("结果为%.2f\n", Caculating(postfix));
	return 0;
}

运行结果如下

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值