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

注:实验用书为 数据结构 C语言版 第2版,人民邮电出版社出版。
实验题目:学生管理系统的设计与实现
实验环境:Visual C++ 6.0或其他C++环境
一、实验目的
1、掌握栈的定义及实现;
2、掌握利用栈求解算术表达式的方法。
二、实验内容
通过修改完善教材中的算法3.4,利用栈来实现算术表达式求值的算法。对算法3.4中调用的几个函数要给出其实现过程:
1、函数In(c):判断c是否为运算符;
2、函数Precede(t1,t2):判断运算符t1和t2的优先级;
3、函数Operate(a,theta,b):对a和b进行二元运算theta。
4、程序运行时,输入合法的算术表达式(中间值及最终结果要在0~9之间,可以包括加减乘除和括号),便可输出相应的计算结果。如下图所示。
这里写图片描述
三、实验吐槽
此代码有很多缺陷,比如只能整数运算。而且单个运算最多到127。即数字运行结果最好在100以内。但可以实现10*10#等运算,这是因为算法的存储环境是char,最大256,而‘0’这个ASCII值又是48,对运算有所限制,但突破了之前的只能一位数字运算。
四、代码
代码主文件(calculator.cpp):

#include<iostream>
#include "stack.h"
#include<stdio.h>
using namespace std;
bool In(char e)//判断读入字符是否为运算符
{
    if(e=='+'||e=='-'||e=='*'||e=='/'||e=='('||e==')'||e=='#')
        return true;//是
    else
        return false;//不是
}
char Precede(char a,char b)//比较运算符的优先级
{//对照数据集书78页的表,a为纵轴值,b为横轴值
    char f;
    if(a=='+'||a=='-')
    {
        if(b=='+'||b=='-'||b==')'||b=='#')
        f='>';
        else if(b=='*'||b=='/'||b=='(')
        f='<';
    }
    else if(a=='*'||a=='/')
    {
        if(b=='+'||b=='-'||b=='*'||b=='/'||b==')'||b=='#')
        f='>';
        else if(b=='(')
        f='<';
    }
    else if(a=='(')
    {
        if(b=='+'||b=='-'||b=='*'||b=='/'||b=='(')
        f='<';
        else if(b==')')
        f='=';
    }
    else if(a==')')
    {
        if(b=='+'||b=='-'||b=='*'||b=='/'||b==')'||b=='#')
        f='>';
    }
    else if(a=='#')
    {
        if(b=='+'||b=='-'||b=='*'||b=='/'||b=='(')
        f='<';
        else if(b=='#')
        f='=';
    }
    return f;
}
int Operate(int i,char theta,int j)//计算a(theta)b结果
{
    int result;
    switch(theta)   {
        case '+': result = i + j; break;
        case '-': result = i - j; break;
        case '*': result = i * j; break;
        case '/': result = i / j; break;
    }
    return result;
}
int read_C(int *n){
    char c;
    *n=0;
    while((c=getchar())==' ');  //跳过一个或多个空格
    if(In(c)){//通过函数判断如果字符不是数字,那么只能是运算符
        *n=c;
        return 1;
    }
    do{//能执行到该条语句,说明字符是数字,此处用循环获得连续的数字
        *n=*n*10+(c-'0'); //把连续的数字字符转换成相对应的整数
        c=getchar();
    }while(!In(c)); //如果下一个字符是数字,进入下一轮循环
    ungetc(c,stdin);//新读入的字符不是数字,可能是运算符,为了不影响下次读入,把该字符放回到输入缓冲区
    return 0;
}
int EvaluateExpression()
{
    SqStack OPND,OPTR;
    int flag;
    int ch;//把读入的字符转换为整数型,即ASCII表值
    char a,b,theta,x;//ch为当前读入字符,theta为运算符,x仅仅只是变量寄存弹出值,对计算表达式无影响。
    InitStack(OPND);//初始化OPND栈,寄存操作数和运算结果
    InitStack(OPTR);//初始化OPTR栈,寄存运算符
    Push(OPTR,'#');
    flag=read_C(&ch);
    while(ch!='#'||GetTop(OPTR)!='#')
    {
        if(flag==0)//如果是运算符,直接压栈读入新字符
        {
        Push(OPND,ch);
        flag=read_C(&ch);
        }
        else
        {
            switch(Precede(GetTop(OPTR),ch))
            {//优先级选择
            case '<':
                Push(OPTR,ch);
                flag=read_C(&ch);
                break;
            case '>':
                Pop(OPTR,theta);
                Pop(OPND,b);
                Pop(OPND,a);
                Push(OPND,Operate(a,theta,b));
                break;
            case '=':
                Pop(OPTR,x);
                flag=read_C(&ch);
                break;
            }
        }
    }
return GetTop(OPND);
}
int main()
{
    cout<<"请输入算术表达式,并以#结束."<<endl;
    cout<<EvaluateExpression()<<endl;
    return 0;
}

代码头文件(stack.h):

#ifndef STACK_H_INCLUDED
#define STACK_H_INCLUDED
#endif // STACK_H_INCLUDED
#define MAXSIZE 100
#include<stdlib.h>
using namespace std;
typedef char SElemType;
typedef struct
{
    char *base;
    char *top;
    int stacksize;
}SqStack;
void InitStack(SqStack &S)
{
    S.base=new char [MAXSIZE];
    if(!S.base) exit(0);
    S.top=S.base;
    S.stacksize=MAXSIZE;
}
bool Push(SqStack &S,char e)
{
    if(S.top-S.base==S.stacksize) return false;
    *S.top++=e;
    return true;
}
bool Pop(SqStack &S,char &e)
{
    if(S.top==S.base) return false;
    e=*--S.top;
    //cout<<"pop="<<*S.top;
    return true;
}
char GetTop(SqStack S)
{
    if(S.top!=S.base)
        return *(S.top-1);
}

另外提供一种我第一次实践的方法,这里的算数表达式只能计算1位数值。

#include<iostream>
#include "stack.h"
#include<stdio.h>
using namespace std;
bool In(char e)//判断读入字符是否为运算符
{
    if(e=='+'||e=='-'||e=='*'||e=='/'||e=='('||e==')'||e=='#')
        return true;//是
    else
        return false;//不是
}
char Precede(char a,char b)//比较运算符的优先级
{//对照数据集书78页的表,a为纵轴值,b为横轴值
    char f;
    if(a=='+'||a=='-')
    {
        if(b=='+'||b=='-'||b==')'||b=='#')
        f='>';
        else if(b=='*'||b=='/'||b=='(')
        f='<';
    }
    else if(a=='*'||a=='/')
    {
        if(b=='+'||b=='-'||b=='*'||b=='/'||b==')'||b=='#')
        f='>';
        else if(b=='(')
        f='<';
    }
    else if(a=='(')
    {
        if(b=='+'||b=='-'||b=='*'||b=='/'||b=='(')
        f='<';
        else if(b==')')
        f='=';
    }
    else if(a==')')
    {
        if(b=='+'||b=='-'||b=='*'||b=='/'||b==')'||b=='#')
        f='>';
    }
    else if(a=='#')
    {
        if(b=='+'||b=='-'||b=='*'||b=='/'||b=='(')
        f='<';
        else if(b=='#')
        f='=';
    }
    return f;
}
char Operate(char a,char theta,char b)//计算a(theta)b结果
{
    char c;
    a=a-'0';//把char类型数据转换为数值型数据,方便运算。·
    b=b-'0';
    if(theta=='+')
    c=a+b+'0';
    else if(theta=='-')
    c=a-b+'0';
    else if(theta=='*')
    c=a*b+'0';
    else if(theta=='/')
    c=a/b+'0';
    return c;
}
int EvaluateExpression()
{
    SqStack OPND,OPTR;
    char ch,a,b,theta,x;//ch为当前读入字符,theta为运算符,x仅仅只是变量寄存弹出值,对计算表达式无影响。
    InitStack(OPND);//初始化OPND栈,寄存操作数和运算结果
    InitStack(OPTR);//初始化OPTR栈,寄存运算符
    Push(OPTR,'#');
    ch=getchar();
    while(ch!='#'||GetTop(OPTR)!='#')
    {
        if(!In(ch))
        {
        Push(OPND,ch);
        cin>>ch;//相当于ch=getchar();
        }
        else
        {
            switch(Precede(GetTop(OPTR),ch))
            {
            case '<':
                Push(OPTR,ch);
                cin>>ch;
            break;
            case '>':
                Pop(OPTR,theta);
                Pop(OPND,b);
                Pop(OPND,a);
                Push(OPND,Operate(a,theta,b));
                break;
            case '=':
                Pop(OPTR,x);
                cin>>ch;
                break;
            }
        }
    }
return GetTop(OPND)-'0';
}
int main()
{
    cout<<"请输入算术表达式,并以#结束."<<endl;
    cout<<EvaluateExpression()<<endl;
    return 0;
}

五、流程图

这里写图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值