表达式求值(C语言实现)

描述

算数四则运算的规则是1)先乘除,后加减;2)从左算到右;3)先括号内,后括号外。
由此,算式4+23-10/5的计算顺序为4+23-10/5=4+6-10/5=4+6-2=8。
给定一个以“#”作为结束符的算式,求出算式的结果。

输入

以“#”结尾的表达式,运算数为正整数。每个表达式占一行。

输出

输出表达式运算的结果。

样例输入

4+2*3-10/5#
3*(7-2)#
2*3/2#

样例输出

8
15
3

提示

使用栈来解决本题,很多人都会想到。但怎样建栈,却带来了问题。同样,严书上的代码实际上也给大家带来了问题。看过严书光盘中代码的人应该知道,代码中使用了两个栈,一个是存储运算符的,类型为char;另一个存储运算数,类型为float。而操作两个栈的函数都一样。要知道,除非像C++中使用泛型,C语言中却基本不能实现这样的操作。所以在C语言环境中需要将这两个栈结合在一起。由于char与int有种特别的联系,可以使用int来代替char存储运算符。

置运算符栈为空栈,表达式的起始符'#'为栈底元素。依次读入表达式的每个字符,若是操作数则进OPND栈,若是运算符O则和OPTR栈的栈顶元素比较优先权后进行相应操作,直至整个表达式求值完毕(即OPTR栈的栈顶元素和当前读入的字符均为'#'。

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
 
 
#define N 1000+10
#define STACK_INIT_SIZE 100
#define STACKINCREMENT 10
#define OK 1
#define OVERFLOW 0
#define ERROR 0
 
char str[N];
typedef  int Status;
typedef  int SElemType;
 
typedef struct{
	SElemType *base;
	SElemType *top;
	int stacksize;
}SqStack;
 
unsigned char prior[7][7] = {
{'>','>','<','<','<','>','>'},
{'>','>','<','<','<','>','>'},
{'>','>','>','>','<','>','>'},
{'>','>','>','>','<','>','>'},
{'<','<','<','<','<','=',' '},
{'<','<','<','<','<',' ','>'},
{'<','<','<','<','<',' ','='}};
 
char OPSET[7] = {'+','-','*','/','(',')','#'};
 
Status InitStack(SqStack *s)//初始化栈 
{
	s->base = (SElemType*)malloc(STACK_INIT_SIZE*sizeof(SElemType));
	if(!s->base)
		exit(OVERFLOW);
	s->top = s->base ;
	s->stacksize = STACK_INIT_SIZE;
	return OK;
}
 
Status Push(SqStack *s,SElemType c)//入栈 
{
	if((s->top - s->base ) >= s->stacksize )
	{
		s->base = (SElemType*)realloc(s->base ,(s->stacksize +STACKINCREMENT)*sizeof(SElemType));
		if(!s->base )
			exit(OVERFLOW);
		s->stacksize += STACKINCREMENT;
	}
	*(s->top)++ = c;
	return OK;
}
 
Status GetTop(SqStack *s)//取栈顶元素 
{
	SElemType e;
	if(s->base == s->top )
		return ERROR;
	e = *(s->top-1)    ;
	return e;
}
 
Status In(char c,char str[])//判断是否为运算符 
{
	int i = 0;
	while(c != str[i])
	{
		i++;
	}
	if(i < 7)
		return OK;
	return ERROR;
}
 
void  Strcat(char *str1,char *str2)//字符串连接函数,把字符串str2连接到str1后 
{
	int i = 0, j = 0;
	while(str1[i]!='\0')
	{
		i++;
	}
	while(str2[j]!='\0')
	{
		str1[i++] = str2[j++];
	}
	str1[i] = '\0';
} 
 
Status Atoi(char *c)//把字符串转为数字 
{
	int data= 0,d = 0;
	int i = 0;
	while(c[i]!='\0')
	{
		data = data*10 + c[i]-'0';
		i++;
	}
	return data;	
} 
 
Status precede(int a,char b)//判断优先级函数 
{
	int i = 0,j = 0;
	while(OPSET[i] != a)
	{
		i++;
	}
	while(OPSET[j] != b)
	{
		j++;
	}
	return prior[i][j];
}
 
Status Pop(SqStack *s)//脱括号函数 
{
	int e;
	if(s->base == s->top )
		return ERROR;
	e = *--(s->top);
	return e;
}
 
Status Opereta(int a,int b,int c)//运算函数 
{
	switch(b)
	{
		case '+':
			return a+c;
		case '-':
			return a-c;
		case '*':
			return a*c;
		case '/':
			return a/c;
	} 
}
 
int EvaluateExpression(char *MyExpression)//算法3.4 
{//算术表达式求值的算符优先算法。
//设OPTR和OPND分别为运算符栈和运算数栈
	SqStack OPTR;//运算符栈,字符元素 
	SqStack OPND;//运算数栈,实数元素 
	
	char TempData[20];
	int data,a,b;
	char *c,Dr[2],e;
	int theta;
	
	InitStack(&OPTR);
	Push(&OPTR,'#');
	InitStack(&OPND);
	
	c = MyExpression;
	TempData[0] = '\0';
	while(*c != '#'|| GetTop(&OPTR) != '#')
	{
		
		if(!In(*c,OPSET))//不是运算符则进栈 
		{
			Dr[0] = *c;
			Dr[1] = '\0';
			Strcat(TempData,Dr);
			c++; 
			if(In(*c,OPSET))//是运算符时 
			{
				data = Atoi(TempData);
				Push(&OPND,data);
				TempData[0] = '\0';
			}
		}
		else
		{
			switch(precede(GetTop(&OPTR),*c))
			{
				case '<':
					Push(&OPTR,*c);
					c++;
					break;
				case '=':
					Pop(&OPTR);
					
					c++;
					break;
				case '>':
					a = Pop(&OPND);
					b = Pop(&OPND);
					theta = Pop(&OPTR);
					Push(&OPND,Opereta(b,theta,a));
					break;
			}
		}
	}
	
	return GetTop(&OPND);
}
int main()
{
	
	while(scanf("%s",str)!=EOF)
	{
		printf("%d\n",EvaluateExpression(str));
	}
	return 0;
 } 

 

  • 11
    点赞
  • 93
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
C语言中,可以使用栈来实现表达式求值。具体步骤如下: 1. 定义两个栈,一个用于存储操作数,一个用于存储运算符。 2. 从左到右遍历表达式中的每个元素,如果是操作数,则将其压入操作数栈中;如果是运算符,则将其与运算符栈顶元素进行比较,如果优先级较高,则将其压入运算符栈中;否则,将运算符栈顶元素弹出,与操作数栈顶的两个元素进行运算,并将结果压入操作数栈中,直到当运算符可以压入运算符栈中。 3. 当表达式遍历完毕后,如果运算符栈中还有元素,则依次弹出运算符栈顶元素,并将操作数栈顶的两个元素进行运算,并将结果压入操作数栈中,直到运算符栈为空。 4. 最终,操作数栈中只剩下一个元素,即为表达式的值。 下面是一个简单的实现示例: ```c #include <stdio.h> #include <stdlib.h> #include <ctype.h> #define MAX_SIZE 100 typedef struct { int data[MAX_SIZE]; int top; } Stack; void init(Stack *s) { s->top = -1; } int is_empty(Stack *s) { return s->top == -1; } int is_full(Stack *s) { return s->top == MAX_SIZE - 1; } void push(Stack *s, int x) { if (is_full(s)) { printf("Stack overflow\n"); exit(1); } s->data[++s->top] = x; } int pop(Stack *s) { if (is_empty(s)) { printf("Stack underflow\n"); exit(1); } return s->data[s->top--]; } int peek(Stack *s) { if (is_empty(s)) { printf("Stack underflow\n"); exit(1); } return s->data[s->top]; } int priority(char op) { switch (op) { case '+': case '-': return 1; case '*': case '/': return 2; case '(': return 0; default: printf("Invalid operator: %c\n", op); exit(1); } } int evaluate(char *expr) { Stack opnd, optr; init(&opnd); init(&optr); while (*expr) { if (isdigit(*expr)) { int num = 0; while (isdigit(*expr)) { num = num * 10 + (*expr - '0'); expr++; } push(&opnd, num); } else if (*expr == '(') { push(&optr, '('); expr++; } else if (*expr == ')') { while (peek(&optr) != '(') { char op = pop(&optr); int b = pop(&opnd); int a = pop(&opnd); switch (op) { case '+': push(&opnd, a + b); break; case '-': push(&opnd, a - b); break; case '*': push(&opnd, a * b); break; case '/': push(&opnd, a / b); break; } } pop(&optr); expr++; } else if (*expr == '+' || *expr == '-' || *expr == '*' || *expr == '/') { while (!is_empty(&optr) && priority(*expr) <= priority(peek(&optr))) { char op = pop(&optr); int b = pop(&opnd); int a = pop(&opnd); switch (op) { case '+': push(&opnd, a + b); break; case '-': push(&opnd, a - b); break; case '*': push(&opnd, a * b); break; case '/': push(&opnd, a / b); break; } } push(&optr, *expr); expr++; } else { printf("Invalid character: %c\n", *expr); exit(1); } } while (!is_empty(&optr)) { char op = pop(&optr); int b = pop(&opnd); int a = pop(&opnd); switch (op) { case '+': push(&opnd, a + b); break; case '-': push(&opnd, a - b); break; case '*': push(&opnd, a * b); break; case '/': push(&opnd, a / b); break; } } return pop(&opnd); } int main() { char expr[MAX_SIZE]; printf("Enter an expression: "); scanf("%s", expr); int result = evaluate(expr); printf("Result: %d\n", result); return 0; } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值