• 题目:算术表达式求值

题目描述:表达式计算是实现程序设计语言的基本问题之一,也是栈的应用的一个典型例子。设计一个程序,演示用运算符优先法对算数表达式求值的过程。
基本要求:以字符序列的形式从终端输入语法正确的、不含变量的整数表达式。利用教科书表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

在这里插入图片描述

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐