数据结构 | 栈结构及其应用

实验内容:算术表达式求值(算术计算器)

一、实验目的

表达式求值是实现程序设计语言的基本问题之一,也是栈的应用的一个典型例子。一个算术表达式是由操作数(operand)、运算符(operator)和界限符(delimiter)组成的。假设操作数是正整数,运算符只含加减乘除等四种二元运算符,界限符有左右括号和表达式起始、结束符“#”,如:#(7+15)*(23-28/4)#。引入表达式起始、结束符是为了方便。设计一个程序,演示算术表达式求值的过程。

二、实验要求及实验环境

实验要求:

  1. 从文本文件输入任意一个语法正确的(中缀)表达式,显示并保存该表达式。
  2. 利用栈结构,把(中缀)表达式转换成后缀表达式,并以适当的方式展示栈的状态变化过程和所得到的后缀表达式。
  3. 利用栈结构,对后缀表达式进行求值,并以适当的方式展示栈的状态变化过程和最终结果。

实验环境:Windows11操作系统+VS Code编译器

三、设计思想

此实验主要分为栈结构的实现以及中缀表达式的处理两个部分

1.栈结构的实现

实验采用顺序栈的结构,利用template方式定义了一个栈的模板类,通过数组data[]储存栈中元素,整数型变量Top作为栈顶指针。

此部分主要实现了以下功能:

序号

函数名

函数功能

函数参数

函数返回值

1

Stack()

初始化栈

2

push(n)

压栈

进栈元素n

3

pop()

出栈

栈顶元素d

4

size()

查看栈长度

栈长度length

5

isEmpty()

判断是否栈空

bool变量x

6

top()

读取栈顶元素

栈顶元素d

7

show()

打印当前栈中元素

2.中缀表达式的处理

此部分函数调用已经逻辑关系如下:

  • 首先是对中缀表达式的储存表示。

此过程通过一个字符数组x[]即可实现,

  • 其次是中缀表达式到后缀表达式的转换

这里主要是对运算符“(”“+”“-”“*”“/”“)”的优先级判断。基本算法思想是:对上述字符数组从头至尾扫描,

  1. 遇见数字字符或小数点“.”直接存进后缀表达式的字符数组y[]中;
  2. 如遇到运算符,则判断其与栈顶元素的优先级后,执行对应操作后再进栈。从栈中弹出的运算符依序存进后缀表达式的字符数组y[]。

注意,在此步骤中,由于字符一次扫描一位,为方便可视化以及多位数的计算,在相邻两个字符间以空格间隔,表示多位数的连续数字字符之间则无空格隔开。

优先级如下表所示:

运算符

优先级及相关操作

“(”

无序比较,直接进入栈

“*”或“/”

当栈顶为“*”或“/”时,弹出当前栈顶直至不为“*”或“/”后进栈

“+”或“-”

当栈顶不为“#”或“(”时,弹出当前栈顶直至为“#”或“(”后进栈

“)”

无需进栈,逐个将栈顶弹出直至“(”恰好弹出栈

“#”

第一次直接进栈,第二次直接将栈中元素全部弹出。

  • 最后是对后缀表达式的求值

基本思想是从头至尾扫描后缀表达式y[],

  1. 遇到数字字符时通过ASCII码将其转换为float数据类型后压入栈中,
  2. 遇到运算符“+”“-”“*”“/”时,依次弹出栈顶的两个数字进行运算,运算结果压入栈中,继续扫描。

四、测试结果

测试用例:#(7.55+15)*((21-28/3)+3)#,#(2*(3+1)*(4.55+7.3))#

测试结果如下:

五、附录:源代码(带注释)

1. seqstack.h(手动实现顺序栈结构)

#include<iostream>
#define SIZE 50
using namespace std;

template<class T>class Stack
{
    private:
            T data[SIZE]; //顺序储存数据
            int Top; //栈顶下标
    public:
        void stack() //栈的初始化
        { 
            Top = -1;
        }

        void push(T n) //压栈
        {        
            data[Top + 1]  = n;
            Top++;
        }

        T pop() //出栈
        {
            if(Top <= -1)
                abort();
            T d = data[Top];
            Top--;
            return d;
        }

        int size() //查看栈长度
        {
            return Top + 1;
        }

        T top() //读取栈顶元素
        {
            return data[Top];
        }

        bool isEmpty() //判断是否栈空
        {
            if(Top == -1)
                return true;
            else 
                return false;
        }

        void show() //打印当前栈中元素
        {
            for(int i = 0; i<=Top; i++)
                cout<<data[i]<<" ";
            if(Top < 0)
                cout<<"栈空";
        }
};

2. main.cpp(具体功能实现)

#include <iostream>
#include <fstream>
#include "seqstack.h"

using namespace std;
//中缀转后缀
void translate(char x[], char y[]);
//后缀的计算
float calculate(char y[]);
//四则运算
float operate(float x, float y, char c)
{
    switch (c)
    {
    case '*': return (x * y); break;
    case '/': return (y / x); break;
    case '+': return (x + y); break;
    case '-': return (y - x); break;
    default:  break;
    }
}
int main()
{
    char x[SIZE],y[SIZE];
    ifstream infile;
    int i = 0;
    //文件读取
    infile.open("data.txt");
    while(!infile.eof()) //判断文件是否读取完毕
    {
        i++;
        infile.getline(x,SIZE);
        cout<<"============================================="<<endl;
        cout<<"读取的第"<<i<<"个中缀表达式为: "<<x<<endl;
        cout<<"============================================="<<endl;
        cout<<"转换过程中栈的变化过程为:"<<endl;
        translate(x,y);
        cout<<"============================================="<<endl;
        cout<<"后缀表达式为: "<<y<<endl;
        cout<<"============================================="<<endl;
        cout<<"计算过程为: "<<endl;
        float m = calculate(y);
        cout<<"============================================="<<endl;
        cout<<"最后中表达式结果为: "<<m<<endl;
        cout<<"============================================="<<endl;
    }
    infile.close();

}

void translate(char x[], char y[])
{
    Stack<char> s; //定义运算符栈
    s.stack();
    int i = 0, j = 0,number = 0;
    //初始化字符数组
    for(int k = 0; k < SIZE; k++)
        y[k] = ' ';
    //逐个扫描
    while (x[i] != '\0')
    {
        //数字字符
        if (x[i] >= '0' && x[i] <= '9')
        {
            while((x[i + 1] >= '0' && x[i + 1] <= '9' ) || (x[i + 1] == '.'))
                {
                    y[j] = x[i];
                    i++;j++;
                }
            y[j] = x[i]; y[j + 1] = ' ';
            j += 2;
        }
        //运算符处理
        if(x[i] == '#')
        {   
            number++;
            if(number == 1) 
                s.push(x[i]);
            //当第二次遇到#时结束转换
            if(number == 2)
            {
                while(s.top() != '#')
                {
                    char x = s.pop();
                    y[j] = x;
                    y[j + 1] = ' ';
                    j += 2;
                }
                s.show();cout<<'\n';
                char x = s.pop();
                s.show();cout<<'\n';
                return;
            }
        }
        if (x[i] == '(' )
            s.push(x[i]);
        if (x[i] == '*' || x[i] == '/')
        {
            while(s.top() == '*' || s.top() == '/')
            {
                char x = s.pop();
                y[j] = x;
                y[j + 1] = ' ';
                j += 2;
            }
            s.push(x[i]);
        }
        if (x[i] == '+' || x[i] == '-')
        {
            while(s.top() != '#' && s.top() != '(')
            {
                char x = s.pop();
                y[j] = x;
                y[j + 1] = ' ';
                j += 2;
            } 
            s.push(x[i]);
        }
        if(x[i] == ')')
        {
            while(s.top() != '(')
            {
                char x = s.pop();
                y[j] = x;
                y[j + 1] = ' ';
                j += 2;
            }
            char q = s.pop();
        }
        i++;
        //展示当前栈状态
        s.show();
        cout<<'\n';
    }
    // 加入字符串的结尾
    y[j+1] = '\0';
}

float calculate(char y[])
{
    Stack<float> numbers;
    numbers.stack();
    int i = 0;
    while(y[i] != '\0')
    {
        //数字字符处理
        if(y[i] >= '0' && y[i] <= '9')
        {
            float m = 0;
            //整数部分
            while(y[i + 1] >= '0' && y[i + 1] <= '9')
            {
                m += (y[i] - '0');
                m *= 10;
                i++;
            }
            m += (y[i] - '0');
            //小数部分
            if(y[i + 1] == '.')
            {
                i = i + 2;
                float j = 1;
                while(y[i + 1] >= '0' && y[i + 1] <= '9')
                {
                    m += ((float)(y[i] - '0')/(10*j));
                    j *= 10;
                    i++;
                }
                m += ((y[i] - '0')/(10*j));
            }
            numbers.push(m);
        }
        //运算符处理
        if(y[i] == '*' || y[i] == '/' || y[i] == '+' || y[i] == '-' )
        {
            numbers.show();
            cout<<y[i]<<endl;
            float x1,x2;
            x1 = numbers.pop();
            x2 = numbers.pop();
            float x = operate(x1,x2,y[i]);
            //cout<<x<<endl;
            numbers.push(x);
        }
        i++;

    }
    return numbers.pop();
}

  • 15
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值