堆栈实现表达式求值

1.内容和要求

任务:

编程序实现堆栈,并且使用堆栈实现常用算术表达式求解

要求:

1.实现堆栈,包括堆栈的初始化,push和pop操作;

2.输入表达式,使用堆栈实现表达式求解算术结果,输出答案。

测试:2-4*(4-6/3)+3*2

2.解决方案和关键代码

2.1 解决方案

       表达式求值可以看成是由操作数和算符(运算符和界限符)组成的。算术的四则运算的规则:①先乘除,后加减;②从左算到右;③先括号内,后括号外。我们可以根据这个运算的优先关系的规定来实现对表达式的求值。

       为实现算符优先算法,可以使用两个工作栈。一个称作OPTR,用以寄存运算符,另一个称作OPND,用以寄存操作数和运算结果。算法的基本思想是:

ea0d1176cd9a4e76bfc1bdcc52c0b1fd.png

e736a0e156c0466fb778e60bd86afe77.png9e4184c745e042c4ba7e8c64227edf67.png

2.2 关键代码

float evaluation(){
    StackChar OPTR;
    StackFloat OPND;
    
    char TempData[20],Dr[2];
    char theta,c,x;
    float a,b,Data;

    InitStack(OPTR);
    Push(OPTR,'#');
    InitStack(OPND);

    c = getchar();
    while(c!='#' || GetTop(OPTR) != '#'){
        if(!In(c)){
            //不是算术运算符
            Dr[0] = c;
            Dr[1] = '\0';
            strcat(TempData,Dr);
            c = getchar();
            if(In(c)){
                Data = (float)atof(TempData);
                Push(OPND,Data);
                strcpy(TempData,"\0");
            }
        }
        else{
            switch(Precede(GetTop(OPTR),c)){
                case '<':
                    Push(OPTR,c);
                    c = getchar();
                    break;
                case '=':
                    Pop(OPTR,x);
                    c = getchar();
                    break;
                case '>':
                    Pop(OPTR,theta);
                    Pop(OPND,b);
                    Pop(OPND,a);
                    Push(OPND,operate(a,theta,b));
                    break;
            }
        }
    }
    return GetTop(OPND);
}

3.总结与改进

3.1总结

       表达式求值主要集中在算符的优先级如何处理的问题,将操作数和运算符的进出栈加以转化。但在进栈的时候不得不要面临数据类型强制转换的问题。本文采用字符数组,getchar()读入字符后加以判断,当不是运算符时,为增强程序的鲁棒性,还需要再getchar(),每次将操作字符暂时存储在字符数组Dr[1]中,Dr[0]赋值‘/0’,即Dr变成字符数组,Dr再通过strcat函数追加到TempData[20]中,直到再次读取到运算符才把之前的TempData入栈。而strcpy(TempData,”\0”)将TempData初始化。

3.2改进

        本文分别定义了操作数栈和运算符栈,但操作略微繁琐。可将操作数栈和运算符栈合并为同一个栈,通过字符类型进行统一处理,在进出栈时再进行强制类型转换,但是本文为了使得思路更加清晰,暂不使用同一个栈,把问题的焦点集中在操作数和运算符的进出栈选择的操作问题。两者皆有优点。

附录

#include <iostream>
#include <string.h>
#include <algorithm>

using namespace std;

#define STACKSIZE 100

//运算符集合
char OPSET[7]={'+' , '-' , '*' , '/' ,'(' , ')' , '#'};

//运算符间的优先关系
char Prior[7][7] = {
      '>','>','<','<','<','>','>',
      '>','>','<','<','<','>','>',
      '>','>','>','>','<','>','>',
      '>','>','>','>','<','>','>',  
      '<','<','<','<','<','=',' ',
      '>','>','>','>',' ','>','>',
      '<','<','<','<','<',' ','='
};

//运算符栈
typedef struct{
    char *base;
    char *top;
    int stacksize;
}StackChar;

//操作数栈
typedef struct{
    float *base;
    float *top;
    int stacksize;
}StackFloat;

void InitStack(StackChar &S){
    //运算符栈初始化
    S.base = new char[STACKSIZE];
    if(!S.base) 
        return;
    S.top = S.base;
    S.stacksize = STACKSIZE;
}

void InitStack(StackFloat &S){
    //操作数栈初始化
    S.base = new float[STACKSIZE];
    if(!S.base) 
        return;
    S.top =S.base;
    S.stacksize = STACKSIZE;
}

void Push(StackChar &S,char e){
    //运算符压栈
    if(S.top-S.base==S.stacksize)
        return;
    *S.top++ = e;
}

void Push(StackFloat &S,float e){
    //操作数压栈
    if(S.top-S.base==S.stacksize)
        return;
    *S.top++ = e;

}

void Pop(StackChar &S,char &e){
    //运算符出栈
    if(S.top == S.base) exit(-1);
    e = *--S.top;
}

void Pop(StackFloat &S,float &e){
    //运算符出栈
    if(S.top == S.base) exit(-1);
    e = *--S.top;
}

char GetTop(StackChar S){
    //运算符栈顶元素
    return *(S.top-1);
}

float GetTop(StackFloat S){
    //运算符栈顶元素
    return *(S.top-1);
}

bool In(char c){
    //判断是否为运算符
    for(int i=0; i<7; i++){
        if(c==OPSET[i])
            return true;
    }
    return false;
}

int Position(char c){
    //表中的位置
    for(int i=0; i<7; i++){
        if(c == OPSET[i])
            return i;
    }
    return 0;
}

char Precede(char c1,char c2){
    //表中的优先关系
    return Prior[Position(c1)][Position(c2)];
}

float operate(float a,char theta,float b){
    float result;
    switch(theta){
        case '+':
            result = a+b;
            break;
        case '-':
            result = a-b;
            break;
        case '*':
            result = a*b;
            break;
        case '/':
            result = a/b;
            break;
        default:
            result = 0;
    }
    return result;
}

float evaluation(){
    StackChar OPTR;
    StackFloat OPND;
    
    char TempData[20],Dr[2];
    char theta,c,x;
    float a,b,Data;

    InitStack(OPTR);
    Push(OPTR,'#');
    InitStack(OPND);

    c = getchar();
    while(c!='#' || GetTop(OPTR) != '#'){
        if(!In(c)){
            //不是算术运算符
            Dr[0] = c;
            Dr[1] = '\0';
            strcat(TempData,Dr);
            c = getchar();
            if(In(c)){
                Data = (float)atof(TempData);
                Push(OPND,Data);
                strcpy(TempData,"\0");
            }
        }
        else{
            switch(Precede(GetTop(OPTR),c)){
                case '<':
                    Push(OPTR,c);
                    c = getchar();
                    break;
                case '=':
                    Pop(OPTR,x);
                    c = getchar();
                    break;
                case '>':
                    Pop(OPTR,theta);
                    Pop(OPND,b);
                    Pop(OPND,a);
                    Push(OPND,operate(a,theta,b));
                    break;
            }
        }
    }
    return GetTop(OPND);
}

int main(){
    cout<<"表达式(#号结束输入)"<<endl;
    float a;
    a = evaluation();
    cout<<"结果是"<<endl;
    cout<<a<<endl;
    return 0;
}

本文的实现思路来自教材53页;

本程序的数据类型转换思路来自以此博客:

数据结构(19)栈典型问题之C++实现表达式求值_YuYunTan的博客-CSDN博客

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值