算术表达式求值(C语言栈)

  • 题目:算术表达式求值

题目描述:表达式计算是实现程序设计语言的基本问题之一,也是栈的应用的一个典型例子。设计一个程序,演示用运算符优先法对算数表达式求值的过程。
基本要求:以字符序列的形式从终端输入语法正确的、不含变量的整数表达式。利用教科书表3.1给出的运算符优先关系,实现对算数四则混合运算表达式的求值,并仿照教科书的例3.1演示在求值中运算符栈、运算数栈、输入字符和主要操作的变化过程。
测试数据:
1+2+3+4
88-15
1024/4
8
1024/(48)
(20+2)
(6/2)
3-3-3
2*(6+2*(3+6*(6+6)))
(((6+6)*6+3)*2+6)*2

  • 算法思想

首先,将输入的字符分为两种类型:运算数运算符。顾名思义,运算数就是参与运算的整数。运算符指加减乘除,左右括号以及‘#’,其中‘#’用于标记输入的开始与结束,起一个标识的作用。也就是说,用户的输入必须以‘#’作为结束。
为实现上述程序功能,选择栈用于存储运算符与运算数,分别用两个栈oprtnum来存储。首先在oprt栈中压入一个‘#’,用以提示程序表达式的边界。从终端读取数据:
如果读到的是数字字符,那么表明现在正在输入的是运算数。为了得到完整的数字,先将这些数字字符按顺序存储到缓冲区(temp栈),直到读到运算符时,将缓冲区的数字按照权重相加,构造出完整的运算数,压入运算数栈中去,同时清空temp栈。
如果读到的是运算符,那么按照规则比较oprt栈顶运算符和此运算符的优先级:(下列三种情况)
a.oprt栈顶运算符高于此运算符,则表明此时已经可以进行计算。将num栈依次出栈两个元素A,B,则由B、oprt栈顶运算符、A构成了一个简单的表达式,对之进行计算,将结果压入num栈。
b.oprt栈顶运算符低于此运算符,则先将这个运算符入栈,然后继续读取。
c.oprt栈顶运算符优先级等于此运算符,例如左右括号匹配时、表达式头‘#’和尾‘#’匹配时,则不将此运算符入栈,反而将oprt栈顶运算符出栈。

重复上述①②操作,直到oprt栈顶元素为‘#’或读取到的字符为‘#’(结束)。此时num栈顶元素即为此表达式的结果。

在这里插入图片描述
上图为运算优先级关系图

  1. 上代码
#include<stdio.h>
#include<stdlib.h>
#define defaultsize 10
#define increasesize 5
typedef struct{
	char *base;
	char *top;
	int stacksize;//栈的存储容量 
}OPRTstack;
typedef struct{
	double *base;
	double *top;
	int stacksize;
}NUMstack;
int createStack(OPRTstack*s)
{
	s->base=(char*)malloc(sizeof(char)*defaultsize);
	if(!s->base)return 0;
	s->top=s->base;
	s->stacksize=10;
	return 1;
}
int pop(OPRTstack *s,char *e)
{
	if(s->top==s->base)return 0;
	s->top--;
	*e=*(s->top);
	return 1;
}
int push(OPRTstack*s,char e)
{
	if(s->top-s->base>=s->stacksize)
	{
		s->base=(char*)realloc(s->base,sizeof(char)*(s->stacksize+increasesize));
		if(!s->base)return 0;
		s->top=s->base+s->stacksize;
		s->stacksize+=increasesize;

	}
	*(s->top)=e;
	s->top++;
}
int isEmpty(OPRTstack *s)
{
	if(s->top==s->base)return 1;
	else return 0;
}
char GetTop(OPRTstack *s)
{
	if(!isEmpty(s))
	{
		char*temp=s->top;
		temp--;
		return *(temp);
	}
	else return '!';//这样定义的话,栈里面不能存储!这个数据 
}
void showStack(OPRTstack*s)
{
	if(isEmpty(s))return ;
	for(int i=0;i<s->top-s->base;i++)
	{
		printf("%c ",s->base[i]);
	}
	printf("  ");
}
//看起来代码很多,其实下面的函数定义和上面的几乎一模一样,只是传递的参数不同而已

int createStack(NUMstack*s)
{
	s->base=(double*)malloc(sizeof(double)*defaultsize);
	if(!s->base)return 0;
	s->top=s->base;
	s->stacksize=10;
	return 1;
}
int pop(NUMstack *s,double *e)
{
	if(s->top==s->base)return 0;
	s->top--;
	*e=*(s->top);
	return 1;
}
int push(NUMstack*s,double e)
{
	if(s->top-s->base>=s->stacksize)
	{
		s->base=(double*)realloc(s->base,sizeof(double)*(s->stacksize+increasesize));
		if(!s->base)return 0;
		s->top=s->base+s->stacksize;
		s->stacksize+=increasesize;

	}
	*(s->top)=e;
	s->top++;
}
int isEmpty(NUMstack *s)
{
	if(s->top==s->base)return 1;
	else return 0;
}
double GetTop(NUMstack *s)
{
	if(!isEmpty(s))
	{
		double *temp=s->top;
		temp--;
		return *(temp);
	}
	else return -1;//这样定义的话,栈里面不能存储!这个数据 
}
void showStack(NUMstack*s)
{
	if(isEmpty(s))return ;
	for(int i=0;i<s->top-s->base;i++)
	{
		printf("%f ",s->base[i]);
	}
	printf("  ");
}



int isOPRT(char c)//判断c是不是运算符 
{
	if(c=='+'||c=='-'||c=='*'||c=='/'||c=='('||c==')'||c=='#')return 1;
	else return 0;
}
char compare(char a,char b)
{
	if(a=='+')
	{
		if(b=='*'||b=='/'||b=='(') return '<';
		else return '>';
	}
	else if(a=='-')
	{
		if(b=='*'||b=='/'||b=='(') return '<';
		else return '>';
	}
	else if(a=='*')
	{
		if(b=='(')return '<';
		else return '>';
	}
	else if(a=='/')
	{
		if(b=='(')return '<';
		else return '>';
	}
	else if(a=='(')
	{
		if(b==')')return '=';
		else if(b=='#') return '!';
		else return '<';
	}
	else if(a==')')
	{
		if(b=='(')return '!';
		else return '>';
		
	}
	else if(a=='#')
	{
		if(b==')')return '!';
		if(b=='#')return '=';
		else return '<';
	}
}
double calculate(double left,double right, char operators)
{
	switch(operators)
	{
		case '+':
			return left+right;
			
		case '-':
			return 1.0*left-right;
			
		case '*':
			return left*right;
			
		case '/':
			return 1.0*left/right;
	}
}


int main()
{
	OPRTstack oprt;//运算符栈 
	NUMstack  num;//运算数字栈 
	NUMstack temp;//缓冲区,用于构建完整的运算数字 
	int build=0;//由若干数位构成的数字 
	double index;//某个数位上的数字 
	int complex=1;//10的幂次 
	char operators;//基本表达式中的四则运算符 
	double left,right;//基本表达式中左右运算数字 
	createStack(&num);
	createStack(&oprt);
	createStack(&temp);
	printf("键入运算表达式,以#结束\n"); 
	push(&oprt,'#');
	char c=getchar();
	int error=0;//syntax error 标识符 
	while(c!='#'||GetTop(&oprt)!='#')
	{
		while(!isOPRT(c))//读入的是数字 
		{
			push(&temp,c-'0');
			c=getchar();
		}
		while(!isEmpty(&temp))//将读取到的数字字符存入缓冲区,构建完整的运算数字 
		{
			pop(&temp,&index);
			build+=(index*complex);
			complex*=10 ;
			
		}
		complex=1;
		if(build)push(&num,double(build));//将此运算数字压入栈num 
		printf("\n运算符栈:");
		showStack(&oprt);
		printf("运算数栈:");
		showStack(&num);//每次压栈弹栈都需要打印信息 
		build=0;
		
		if(isOPRT(c))//读入的是运算符 
		{
			switch(compare(GetTop(&oprt),c)){
				case '<':
					push(&oprt,c);
					c=getchar();
					printf("\n运算符栈:");
					showStack(&oprt);
					printf("运算数栈:");
					showStack(&num); 
					break;
					
				case '=':
					pop(&oprt,&operators);
					c=getchar();
					printf("\n运算符栈:");
					showStack(&oprt);
					printf("运算数栈:");
					showStack(&num);
					break;
					
				case '>':
					pop(&oprt,&operators);
					pop(&num,&right);
					pop(&num,&left);
					push(&num,calculate(left,right,operators));//从num栈弹出两个运算数字,利用运算符栈顶元素进行计算 
					printf("\n运算符栈:");
					showStack(&oprt);
					printf("运算数栈:");
					showStack(&num);
					break;
					
				case '!':
					printf("Syntax Error!");
					error=1;
					break;
			}
				
					
			
		}
		if(error)break;
	}
	if(!error)printf("结果为:%f",GetTop(&num));
	return 0;
}
  • 运行结果
    测试数据8:(((6+6)*6+3)*2+6)*2#
    输出:312.000000

在这里插入图片描述

这道题可以使用来解决。当遇到数字时,将其压入中;当遇到操作符时,从中取出两个数字进行计算,将计算结果再次压入中。 具体步骤如下: 1. 定义一个和一个指针,指向字符串的开头。 2. 从左到右遍历字符串,如果遇到数字,将其转化为数字并压入中;如果遇到操作符,则从中取出两个数字进行计算,将计算结果压入中。 3. 最后中剩下的数字即为表达式的值。 C语言代码如下: #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #define MAX_STACK_SIZE 20 // 定义 typedef struct { int top; // 顶指针 int data[MAX_STACK_SIZE]; // 元素数组 } stack; // 初始化 void init_stack(stack *s) { s->top = -1; } // 判断是否为空 int is_empty(stack *s) { return s->top == -1; } // 判断是否已满 int is_full(stack *s) { return s->top == MAX_STACK_SIZE - 1; } // 入 void push(stack *s, int x) { if(is_full(s)) { printf("Error: Stack is full!\n"); exit(1); } s->data[++s->top] = x; } // 出 int pop(stack *s) { if(is_empty(s)) { printf("Error: Stack is empty!\n"); exit(1); } return s->data[s->top--]; } // 获取顶元素 int top(stack *s) { if(is_empty(s)) { printf("Error: Stack is empty!\n"); exit(1); } return s->data[s->top]; } // 判断是否为操作符 int is_operator(char c) { return (c == '+' || c == '-' || c == '*' || c == '/'); } // 计算两个数字的结果 int eval(int x, int y, char op) { switch(op) { case '+': return x + y; case '-': return x - y; case '*': return x * y; case '/': return x / y; default: printf("Error: Invalid operator!\n"); exit(1); } } // 计算表达式的值 int evaluate(char *expr) { stack s; init_stack(&s); int i = 0, n = strlen(expr); while(i < n) { if(isdigit(expr[i])) { // 如果是数字 int x = 0; while(i < n && isdigit(expr[i])) { x = x * 10 + (expr[i] - '0'); i++; } push(&s, x); // 将数字入 } else if(is_operator(expr[i])) { // 如果是操作符 int y = pop(&s); // 取出顶两个数字 int x = pop(&s); int res = eval(x, y, expr[i]); // 计算结果 push(&s, res); // 将结果入 i++; } else { // 如果是空格或其他字符,直接跳过 i++; } } return pop(&s); // 最后中剩下的数字即为表达式的值 } int main() { char expr[MAX_STACK_SIZE]; printf("Input an arithmetic expression: "); gets(expr); int res = evaluate(expr); printf("Result: %d\n", res); return 0; }
评论 22
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值