【数据结构】——中缀表达式求值

题目要求

从键盘输入中缀表达式,建立操作数与运算符堆栈,计算并输出表达式的求值结果。
基本要求:实现 +, -, *, /四个二元运算符以及();操作数范围为0至9。
提高要求:实现+, -两个一元运算符(即正、负号);操作数可为任意整型值(程序可不考虑计算溢出)。
若两个整数相除,结果只保留整数商(余数丢弃);可不处理表达式语法错误。

涉及知识点

栈与队列

数据结构设计

采用C++的模板类,分别创建元素类型为整型的操作数栈OPND和字符型的运算符栈OPTR,每个栈对象中,elem指针用来建立长度为n的数组,n表示栈中元素的最大个数,top表示栈顶指针。

算法描述

①中缀表达式以'#'结束,'#'字符也做运算符处理。
②'('、')'作为运算符处理,括号内运算结束后需要消除括号。
③需要建立两个不同类型的栈,整型的操作数栈OPND和字符型的运算符栈OPTR。
④算法主要步骤:
a. 初始时,OPND置空,'#'作为OPTR栈底元素;
b. 依次读入表达式中的每个字符,若是操作数,直接压入OPND栈;
c. 若是运算符(记为θ),则和OPTR栈顶运算符(记为λ)比较优先级;
λ<θ,λ压入OPTR栈,继续读下一个字符;
λ=θ,脱括号,继续读下一个字符;
λ>θ,执行λ运算(λ退栈),θ等在栈外(不读下一个字符),即θ继续和OPTR 栈顶运算符比较优先级(重复进行以上操作),直至θ能入栈。
⑤对于一元运算符(即正、负号),用'P'代表'+','N'代表'-'。

程序代码

#include<iostream>
using namespace std;
template <typename T>
class Stack                     //模板类:栈
{
public:
    Stack();                //默认构造函数
    Stack(int n);           //构造函数,调用函数createStack(int n),创建长度为n的栈
    ~Stack();               //虚构函数
    int createStack(int n); //创建长度为n的栈
    int empty();            //判断栈是否为空
    int full();             //判断栈是否为满
    int push(T e);          //将元素e压栈
    int pop(T &e);          //元素出栈,保存在e中
    T get_top();            //得到栈顶元素
    friend int isoperator(char &e);//判断字符e是否为运算符
    friend int isp(char &e);//返回栈中运算符的优先级
    friend int icp(char &e);//返回栈外运算符的优先级
    friend int compute(int x, char a, int y);//求值函数
private:
    T *elem;                //建立长度为n的数组
    int n;                  //栈中元素的最大个数
    int top;                //栈顶指针
};
template<typename T>
Stack<T>::Stack()
{
    top = -1;
}
template<typename T>
Stack<T>::Stack(int n)
{
    createStack(n);
}
template<typename T>
Stack<T>::~Stack()
{
    n = 0;
    top = -1;
    delete[]elem;
}
template<typename T>
int Stack<T>::createStack(int n)
{
    if (n <= 0)
        return 0;
    this->n = n;
    top = -1;
    elem = new T[n];
    if (!elem)
        return 0;
    return 1;
}
template<typename T>
int Stack<T>::empty()
{
    return top == -1;
}
template<typename T>
int Stack<T>::full()
{
    return top >= n - 1;
}
template<typename T>
int Stack<T>::push(T e)
{
    if (top >= n - 1)
        return 0;
    elem[++top] = e;
    return 1;
}
template<typename T>
int Stack<T>::pop(T & e)
{
    if (top == -1)
        return 0;
    e = elem[top--];
    return 1;
}
template<typename T>
T Stack<T>::get_top()
{
    return elem[top];
};
int isoperator(char &e)        //判断是否为运算符
{
    if (e == '+' || e == '-' || e == '*' || e == '/' || e == '(' || e == ')' || e == '#' || e == 'P' || e == 'N')
        return 1;      //是运算符返回1
    else
        return 0;      //不是运算符返回0
}
int isp(char &e)               //返回栈中运算符的优先级
{
    switch (e)
    {
    case '#':
        return 0; break;
    case '(':
        return 1; break;
    case '+':
    case '-':
        return 2; break;
    case '*':
    case '/':
        return 3; break;
    case 'P':
    case 'N':
        return 4; break;
    case ')':
        return 5; break;
    default:
        return -1; break;
    }
}
int icp(char &e)                 //返回栈外运算符的优先级
{
    switch (e)
    {
    case '#':
        return 0; break;
    case ')':
        return 1; break;
    case '+':
    case '-':
        return 2; break;
    case '*':
    case '/':
        return 3; break;
    case 'P':
    case 'N':
        return 4; break;
    case '(':
        return 5; break;
    default:
        return -1; break;
    }
}
int compute(int x, char a, int y)
{
    switch (a)
    {
    case '+':                //计算加法
        return x + y; break;
    case '-':                //计算减法
        return x - y; break;
    case '*':                //计算乘法
        return x * y; break;
    case '/':                //计算除法
        return x / y; break;
    default:
        return -1; break;
    }
}
int g1()
{
    char a, b, c;
    int i, j, f, value, firstOpnd, secondOpnd, m;
    Stack<char> OPTR(MAX);    //建立运算符栈
    Stack<int> OPND(MAX);     //建立操作数栈
    OPTR.push('#');           //'#'压栈
    cout << "请输入中缀表达式: ";
    a = getchar();
    while (a != '#' || OPTR.get_top() != '#')
    {
        if (!isoperator(a))   //不是运算符,即为操作数,操作数入栈
            OPND.push(a - 48);//将字符型转化为整型数字
        else                  //是运算符,与栈顶运算符比较优先级大小
        {
            b = OPTR.get_top();//得到栈顶元素
            i = isp(b);       //栈顶运算符的优先级
            j = icp(a);       //栈外运算符的优先级
            if (i < j)        //栈外运算符优先级高,运算符入栈
                OPTR.push(a);
            else
            {
                OPTR.pop(b);                    
                if (b != '('&&i == j || i > j)
                {
                    c = OPTR.get_top();
                    if ((c == '(' || c == '#') && (b == 'P' || b == 'N'))    /*c为一元运
                                                                            算符:正负号*/
                    {
                        OPND.pop(firstOpnd); //得到操作数
                        switch (b)
                        {
                        case 'P':            //正号
                            f = firstOpnd * 1;
                            break;
                        case 'N':            //负号
                            f = firstOpnd * (-1);
                            break;
                        }
                    }
                    else                     //c为二元运算符
                    {
                        OPND.pop(secondOpnd); //得到第二操作数
                        OPND.pop(firstOpnd);  //得到第一操作数
                        f = compute(firstOpnd, b, secondOpnd); //计算求值
                    }
                    OPND.push(f);             //求值结果压栈
                    continue;
                }
            }
        }
        c = a;
        a = getchar();                         //继续读取字符
        while(!isoperator(a) && !isoperator(c))  /*若连续读取字符均为数字,则乘以位权
                                                  得到多位数*/
        {
            OPND.pop(m);
            m = m * 10 + a - 48;
            OPND.push(m);
            c = a;
            a = getchar();
        }
        
    }
    OPND.pop(value);
    return value;      //返回表达式的结果
}
int main()
{
    int a;
    a = g1();
    cout << "运算结果为:  " << a << endl;
    return 0;
}

示例

(1)程序输入:3+5*(9-5)/10#
程序输出:5

(2)程序输入:P9+10*(N2*8/4)-10#
程序输出:-41

(3)程序输入:20-3*25+(N41/3)*100#
程序输出:-1355

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343