栈的应用-算数表达式求值

  1. List item

** 实验要求**

河 南 师 范 大 学
20学年—21学年第 1 学期 数据结构实验任务书
专业名称: 实验学时: 4
课程名称:数据结构 任课教师: 王亚丽
实验题目:栈的应用-算术表达式求值
实验环境: Visual C++ 2010  
实验目的:
1.掌握栈的定义及实现;
2.掌握利用栈求解算术表达式的方法。
实验内容:
通过修改完善教材中的算法3.4,利用栈来实现算术表达式求值的算法。对算法3.4中调用的几个函数要给出其实现过程:
(1) 函数In©:判断c是否为运算符;
(2) 函数Precede(t1,t2):判断运算符t1和t2的优先级;
(3) 函数Operate(a,theta,b):对a和b进行二元运算theta。
程序运行时,输入合法的算术表达式(中间值及最终结果要在0~9之间,可以包括加减乘除和括号),便可输出相应的计算结果。如下图:

实验提示:(仅供参考,每个函数的具体实现可以有多种方法,希望有创新)

  1. 将栈的定义和实现单独保存在头文件“stack.h”中,然后在表达式求值的源程序sy2.cpp中包含此头文件(即#include“stack.h”)。
    2.表达式求值源程序sy2.cpp的具体实现
    (1) 主函数如下:
    void main()
    {
    cout<<“请输入算术表达式,并以#结束.”<<endl;
    cout<<EvaluateExpression()<endl;
    }
    (2) 函数EvaluateExpression的实现见算法3.10
    (3) 函数In©的实现可以采用以下方式:
    Status In(SElemType c)// 应在前面有定义typedef char SElemType;
    { // 判断c是否为运算符
    switch©
    {
    case’+’:return TRUE;
    ……//补充完整
    default:return FALSE;
    }
    }
    (4) 函数Precede(t1,t2)的实现可以采用以下形式:
    SElemType Precede(SElemType t1,SElemType t2)
    { //根据教材表3.1,判断两个运算符的优先关系
    SElemType f;
    switch(t2)
    {
    case ‘+’:
    case ‘-’:if(t1==’(’||t1==’#’)
    f=’<’;
    else
    f=’>’;
    break;
    ……//补充完整
    }
    return f;
    }
    (5) 函数Operate(a,theta,b)的实现可以采用以下方式:
    SElemType Operate(SElemType a,SElemType theta,SElemType b)
    {
    SElemType c;
    a=a-48;
    b=b-48;
    switch(theta)
    {
    case’+’:c=a+b+48;
    break;
    ……//补充完整
    }
    return c;
    }

选做内容1:进一步改进,使表达式的中间值及最终结果不局限于0~9之间的个位数。(如果完成要在实验报告中注明),如下图:

选做内容2:
将表达式转化成后缀表达式输出,利用后缀表达式求表达式的值并输出。
将中缀表达式转化成后缀表达式存储在队列中,然后利用后缀表达式求表达式的值并输出。
将中缀表达式转化成后缀的思想:
(1)创建一空队列,用来存放后缀表达式,建立并初始化操作符栈OPTR,将表达式起始符“#”压入OPTR栈。
(2)依次读入表达式中每个字符ch,循环执行(3)至(5),直至求出整个表达式转换完毕。
(3)取出OPTR的栈顶元素,当OPTR的栈顶元素和当前读入的字符ch均为“#”时,整个中缀表达式转换完毕。
(4)若ch不是运算符,则进队,读入下一字符ch。
(5)若ch是运算符,则根据OPTR的栈顶元素和ch的优先权比较结果,做不同的处理。
① 若是小于,则ch压入OPTR栈,读入下一字符ch。
② 若是大于,则弹出OPTR栈顶的运算符,进队。
③ 若是等于,则OPTR的栈顶元素是“(”且ch是“)”,这时弹出OPTR栈顶的“(”,相当于去掉括号,然后读入下一字符ch。
对后缀表达式进行计算的具体步骤为:
建立一个栈S从左到右读后缀表达式,读到数字就将它转换为数值压入栈S中,读到运算符则从栈中依次弹出两个数分别到Y和X,然后以“X运算符Y”的形式计算出结果,再压进栈S中。如果后缀表达式未读完,重复执行上面过程,最后输出栈顶的数值即可结束。

实验要求:
(1) 程序要添加适当的注释,程序的书写要采用缩进格式。
(2) 程序要具在一定的健壮性,即当输入数据非法时,程序也能适当地做出反应。
(3) 程序要做到界面友好,在程序运行时用户可以根据相应的提示信息进行操作。
(4) 根据实验报告模板详细书写实验报告,在实验报告中给出表达式求值算法的流程图。
(5) 将栈的定义和实现单独保存在一个头文件“stack.h”中,表达式求值的源程序保存为“calculator.cpp”,实验报告命名为“实验报告2.doc”。将stack.h、calculator.cpp和“实验报告2.doc”三个文件压缩为一个文件,按以下方式命名:学号姓名.rar,上传到移动教学平台。
实验步骤

在头文件中构造栈的相关操作
在这里插入图片描述

首先初始化好两个栈,一个存放数字,一个存放运算符号。接着定义一个数组,将表达式录入进来。(此时,同时也将int型的数字转变为了char型,后面需要减去’0’,恢复其原本数字)
在定义栈的时候,取栈顶元素POP,入栈PUSH,返回栈顶元素GETTOP都应当分别定义两个,一个返回值为int,一个为char,用于应对不同的数据类型,为后续操作做准本。
定义好三个函数:
int In(char ch) // 判断输入的字符是否为运算符
char Precede(char a,char b) //比较两个字符的优先级
int Operate(int a,char theta,int b)//将A和B进行二元运算
遍历数组,若为数字则通过shu=shu*10+str[i]-‘0’;(shu原本等于0),以实现两位数运算;若为符号则调用In函数,根据不同的返回值,进行相应的操作:1,若小于:则将该元素压入OPTR栈。2:若大于若大于,则弹出OPTR栈顶的运算符,从OPND栈弹出两个数,进行相应运算,结果压入OPND栈。3:若等于弹出OPTR栈顶的’(’
最后返回OPND的栈顶元素即为实验结果
在这里插入图片描述
头文件

#define OK 1
#define ERROR 0
#define OVERFLOW -2
#include<stdlib.h>
#include<stdio.h>
typedef char SElemType;
typedef int Status;
#define MAXSIZE 100 //顺序栈存储空间的初始分配
typedef struct {
	SElemType *base;//定义栈底指针
	SElemType *top;//定义栈顶指针
	int stacksize;//定义栈的最大容量
} SqStack;
//构造一个空栈:
 Status InitStack(SqStack &S)
 {
	 S.base=new SElemType[MAXSIZE];
	 if(!S.base) exit(OVERFLOW);
	 S.top=S.base;
	 S.stacksize=MAXSIZE;
	 return OK;
 }
 //入栈:
 Status Push (SqStack& S, Status e)
 {//插入元素e为新的栈顶元素
	 if(S.top-S.base==S.stacksize)
		 return ERROR;
	 *S.top++=e;
	 return OK;
 }
 Status Push2 (SqStack &S, char e)
 {//插入元素e为新的栈顶元素
	 if(S.top-S.base==S.stacksize)
		 return ERROR;
	 *S.top++=e;
	 return OK;
 }
 //出栈:
 Status Pop (SqStack &S,char &e)
 {//删除S的栈顶元素,用e返回其值
	 if(S.top==S.base)
		 return ERROR;
	 e=*--S.top;
	 return OK;
 }
 Status Pop2 (SqStack &S,int &e)
 {//删除S的栈顶元素,用e返回其值
	 if(S.top==S.base)
		 return ERROR;
	 e=*--S.top;
	 return OK;
 }
 //取栈顶元素
 char GetTop(SqStack S)
 {
	 if(S.top!=S.base)
		 return *(S.top-1);
 }
 
 Status GetTop2(SqStack S)
 {
	 if(S.top!=S.base)
		 return *(S.top-1);
 }

源文件

#include<stdio.h>
#include<string.h>
#include<malloc.h>
#include<stdlib.h>
#include<iostream>
#include"Stack.h"
#define OK 1
#define ERROR 0
#define OVERFLOW -2
#define MAXSIZE 100
using namespace std;

 
int In(char ch) // 判断输入字符是否为运算符 
{
	if(ch=='+')	return OK;
	if(ch=='-')	return OK;
	if(ch=='*')	return OK;
	if(ch=='/')	return OK;
	if(ch=='(')	return OK;
	if(ch==')')	return OK;
	if(ch=='#')	return OVERFLOW;
	return ERROR;//如果是数返回0,否则返回1
}
 
char Precede(char a,char b) // 比较符号 a与符号 b的优先级.如 a 优于 b,则返回 ' > ',否则返回 ' < ' 或 ' = ' 
{
	if(b=='+')
	{
		if(a=='('||a=='#')	return '<';
		return '>';
	}
	if(b=='-')
	{
		if(a=='('||a=='#')	return '<';
		return '>';
	}
	if(b=='*')
	{
		if(a=='*'||a=='/'||a==')')	return '>';
		return '<';
	}
	if(b=='/')
	{
		if(a=='*'||a=='/'||a==')')	return '>';
		return '<';
	}
	if(b=='(')	return '<';
	if(b==')')
	{
		if(a=='(')	return '=';
		return '>';
	}
	if(b=='#')
	{
		if(a=='#')	return '=';
		return '>';
	}
}
 
int Operate(int a,char theta,int b) // 把 a、b进行二元运算 
{
	if(theta=='+')	{return (a+b);}
	 else if(theta=='-')	{return (a-b);}
	 else if(theta=='*')	{return (a*b);}
	 else if(theta=='/')	{return (a/b);}
	 else  {return 99999;}
	

}
 
int EvaluateExpression() // 计算过程 
{
	char str[1000];//定义一个大小为100的字符数组用于存放表达式
	SqStack OPTR;
	SqStack OPND;
	InitStack(OPND);//初始化OPND栈
	InitStack(OPTR);//初始化OPTR栈
	char T;//用于存放弹出的字符
	scanf("%s",str);//将输入的表达式保存在数组str中
	Push2(OPTR,'#');
	char theta;
	int shu=0;
	int a=0;
	int b=0;
	int flag=0;
	for(int i=0;str[i];i++)
	{
		if(In(str[i])==0)
		{
			/*因为scanf录入表达式的时候把数字也变成了char型,故需要此处-'0'恢复原本的数值*/
			shu=shu*10+str[i]-'0';//计算两位数运算
			flag=1;
		}
		else/*如果输入的是字符且flag为1(表明前一个元素是数),则将数压入操作数栈,shu,flag则继续恢复为0,
			同时比较该字符与OPTR栈顶字符的优先级*/
		{
			if(flag)
			{
				Push(OPND,shu);
				shu=0;
				flag=0;
			}

			   switch(Precede(GetTop(OPTR),str[i]))// 比较符号 a与符号 b的优先级.若 a 优于 b,则返回 ' > ',否则返回 ' < ' 或 ' = '
			{
				case '<'://若小于,则将该元素压入OPTR栈
					Push2(OPTR,str[i]);
					break;
				case '>'://若大于,则弹出OPTR栈顶的运算符,从OPND栈弹出两个数,进行相应运算,结果压入OPND栈
					Pop(OPTR,theta);
					Pop2(OPND,b);Pop2(OPND,a);
					if (Operate(a,theta,b)==99999)
					{
					printf("您输入的表达式不正确,请重新输入\n");exit(1);}
					else{Push(OPND,Operate(a,theta,b));
					i--;}
					break;
				case '='://OPTR栈顶元素是'('且str[i]是')'
					Pop(OPTR,T);//弹出OPTR栈顶的'('
					break;
			}
		}
	}

	
	return GetTop2(OPND);
}
int main()
{
	cout<<"请输入算数表达式(值及最终结果要保持在两位数,且只能用'+','-','*','/')并以#结束\n"<<endl;

	printf("\n计算结果为:%d\n",EvaluateExpression());
	return 0;
}

结果
在这里插入图片描述
在这里插入图片描述

  • 19
    点赞
  • 149
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值