栈的应用——表达式求值

  表达式求值是程序设计语言编译中的一个基本问题,它的实现就是对“栈”的典型应用。本文针对表达式求值使用的是最简单直观的算法“算符优先法”。

  本文给出两种方式来实现表达式求值,方式一直接利用中缀表达式求值,需要用到两个栈,操作数栈和操作符栈。首先置操作数栈为空栈, 操作符栈仅有“#”一个元素。依次读入表达式中的每个字符,若是操作数则进操作数栈,若是操作符则和操作符栈的栈顶运算符比较优先权作相应操作,直至整个表达式求值完毕。方式二首先把中缀表达式转换为后缀表达式并存储起来,然后利用读出的后缀表达式完成求值,其本质上是方式一的分解过程。

  表达式求值的代码如下:

#include <iostream>
#include "stack"
#include "map"
using namespace std;

/*   只能求一位整数的加减乘除混合运算   */

map<char, pair<int, int>> priority;    // 存放各个操作符的栈内栈外优先级,first是栈内,second是栈外
char infix[50];                        // 存放初始的中缀表达式
char postfix[50];                      // 存放转化的后缀表达式
int result;

void MakePriority()        // 构造运算符优先级表
{
    priority.insert(make_pair(‘#‘, make_pair(0, 0)));    // isp(#)=0, icp(#)=0
    priority.insert(make_pair(‘\n‘, make_pair(0, 0)));   // isp(\n)=0, icp(\n)=0  表达式结尾的‘#‘用‘\n‘代替,这样可以省略表达式末尾的结束符‘#‘
    priority.insert(make_pair(‘(‘, make_pair(1, 6)));    // isp(()=1, icp(()=6
    priority.insert(make_pair(‘*‘, make_pair(5, 4)));    // isp(*)=5, icp(*)=4
    priority.insert(make_pair(‘/‘, make_pair(5, 4)));    // isp(/)=5, icp(/)=4
    priority.insert(make_pair(‘%‘, make_pair(5, 4)));    // isp(%)=5, icp(%)=4
    priority.insert(make_pair(‘+‘, make_pair(3, 2)));    // isp(+)=3, icp(+)=2
    priority.insert(make_pair(‘-‘, make_pair(3, 2)));    // isp(-)=3, icp(-)=2
    priority.insert(make_pair(‘)‘, make_pair(6, 1)));    // isp())=6, icp())=1
}

void InfixToPostfix()        // 把中缀表达式转换为后缀表达式
{
    int i = 0;
    stack<char> optrStack;   // 操作符栈
    char optr;               // optr为栈顶的操作符
    optrStack.push(‘#‘);
    while (!optrStack.empty())
    {

        if (isdigit(infix[i]))  // 是操作数则直接输出(追加到postfix结尾)
        {
            postfix[strlen(postfix)] = infix[i];
            postfix[strlen(postfix) + 1] = ‘\0‘;
            i++;                // 读入中缀表达式的下一个字符
        }
        else                    // 是操作符, 比较优先级
        {
            optr = optrStack.top();    // 取出栈顶操作符
            if (priority[infix[i]].second > priority[optr].first)    // icp(infix[i]) > isp(optr),infix[i]入栈
            {
                optrStack.push(infix[i]);
                i++;
            }
            else if (priority[infix[i]].second < priority[optr].first)// icp(infix[i]) < isp(optr),optr退栈并输出
            {
                postfix[strlen(postfix)] = optr;
                postfix[strlen(postfix) + 1] = ‘\0‘;
                optrStack.pop();
            }
            else        // icp(infix[i]) = isp(optr),退栈但不输出,若退出的是‘(‘,则继续读入下一个字符
            {
                optrStack.pop();
                if (optr == ‘(‘)
                    i++;
            }
        }
    }
}

void CalculateByPostfix()    // 通过后缀表达式求值
{
    int i = 0;
    stack<int> opndStack;    // 操作数栈
    int left, right;         // 左右操作数
    int value;               // 中间结果
    int newOpnd;
    while (postfix[i] != ‘#‘ && i < strlen(postfix))
    {
        switch (postfix[i])
        {
        case ‘+‘:
            right = opndStack.top();   // 从操作数栈中取出两个操作数
            opndStack.pop();
            left = opndStack.top();
            opndStack.pop();
            value = left + right;
            opndStack.push(value);     // 中间结果入栈
            break;
        case ‘-‘:
            right = opndStack.top();
            opndStack.pop();
            left = opndStack.top();
            opndStack.pop();
            value = left - right;
            opndStack.push(value);
            break;
        case ‘*‘:
            right = opndStack.top();
            opndStack.pop();
            left = opndStack.top();
            opndStack.pop();
            value = left * right;
            opndStack.push(value);
            break;
        case ‘/‘:
            right = opndStack.top();
            opndStack.pop();
            left = opndStack.top();
            opndStack.pop();
            if (right == 0)
            {
                cerr << "Divide by 0!" << endl;
            }
            else
            {
                value = left / right;
                opndStack.push(value);
            }
            break;
        default:
            newOpnd = (int)(postfix[i] - 48);  // 操作数直接入栈
            opndStack.push(newOpnd);
            break;
        }
        i++;
    }
    result = opndStack.top();
}

void CalculateByInfix()        // 直接利用中缀表达式求值
{
    int i = 0;
    stack<char> optrStack;     // 操作符栈
    stack<int>    opndStack;   // 操作数栈
    char optr;                 // optr为操作符栈顶的操作符
    int left, right, value;    // 左右操作数以及中间结果
    optrStack.push(‘#‘);
    optr = optrStack.top();
    while (!optrStack.empty())   // 直到操作符栈为空
    {

        if (isdigit(infix[i]))   // 是操作数, 进操作数栈
        {
            value = (int)(infix[i] - 48);
            opndStack.push(value);
            i++;
        }
        else                         // 是操作符, 比较优先级
        {
            optr = optrStack.top();  // 取出操作符栈顶的操作符
            if (priority[infix[i]].second > priority[optr].first)      // icp(infix[i]) > isp(optr),infix[i]入栈
            {
                optrStack.push(infix[i]);
                i++;
            }
            else if (priority[infix[i]].second < priority[optr].first) // icp(infix[i]) < isp(optr),optr退栈并输出
            {
                optrStack.pop();
                right = opndStack.top();    // 从操作数栈中取出两个操作数
                opndStack.pop();
                left = opndStack.top();
                opndStack.pop();
                switch (optr)
                {
                case ‘+‘:
                    value = left + right;
                    opndStack.push(value);   // 中间结果入栈
                    break;
                case ‘-‘:
                    value = left - right;
                    opndStack.push(value);   // 中间结果入栈
                    break;
                case ‘*‘:
                    value = left * right;
                    opndStack.push(value);   // 中间结果入栈
                    break;
                case ‘/‘:
                    if (right == 0)
                    {
                        cerr << "Divide by 0!" << endl;
                    }
                    else
                    {
                        value = left / right;
                        opndStack.push(value);
                    }
                    break;
                default:
                    break;
                }
            }
            else
            {
                optrStack.pop();
                if (optr == ‘(‘)
                    i++;
            }
        }
    }
    result = opndStack.top();
}

int main()
{
    MakePriority();    // 构造运算符优先级表

    cout << "请输入中缀表达式:";
    cin >> infix;

    cout << "直接利用中缀表达式求值为:";
    CalculateByInfix();
    cout << result << endl;

    cout << "转化为后缀表达式:";
    InfixToPostfix();
    for (int i = 0;i < strlen(postfix);i++)
    {
        cout << postfix[i];
    }
    cout << endl;

    cout << "利用后缀表达式求值为:";
    CalculateByPostfix();
    cout << result << endl;

    return 0;
}

  为了方便起见,本文只是简单的设计了一个针对一位整数的四则运算进行求值的算法,对于处理多位整数的四则运算,需要对本文接受输入的数据类型进行“升阶”,把字符数组换成字符串数组,将一个整数的多位数字存入一个字符串进行处理。

时间: 2024-08-01 15:28:20

栈的应用——表达式求值的相关文章

栈应用二(表达式求值)

问题;设计一个程序,演示用算符优先法对算术表达式求值的过程.利用算符优先关系,实现对算术四则混合运算表达式的求值.(1)输入的形式:表达式,例如3+2*6-4     包含的运算符只能有'+' .'-' .'*' .'/'(目前还不兼容括号) :(2)输出的形式:运算结果,例如3+2*6-4=11: (3)程序所能达到的功能:对表达式求值并输出:示例:①3+2*6-4 ②30+20*6-80 ③2*7-3*5-3 思路:1.程序扫描表达式,一个一个的扫描2.当发现这个字符是数字的时候,直接入数栈

数据结构 栈的应用 --表达式求值

一: 中缀表达式求值  思想: 需要2个栈,运算对象栈OPND,运算符栈OPTR, 1:将栈OPND初始化为空,栈OPTR初始化为表达式的定界符# 2:扫描表达式,直到遇到结束符# 2.1:当前字符是运算对象,入栈OPND 2.2:当前字符是运算符且优先级比栈OPTR的栈顶运算符优先级高,入栈OPTR,处理下一个字符 2.3:当前字符是运算符且优先级比栈OPTR的栈顶运算符优先级低,则从栈OPND出栈2个运算对象,从栈OPTR出栈一个运算符进行运算,并将运算结果入栈OPND,处理当前字符 2.4

数据结构(7)----栈与队列之栈的应用四则运算表达式求值

栈与队列之栈的应用四则运算表达式求值 栈在四则运算表达式求值的应用为逆波兰表达式(后缀表达式) 普通算式(中缀表达式):9 + (3 - 1) * 3 + 10 / 2     ---(1) 逆波兰表达式(后缀表达式):9 3 1 - 3 * + 10 2 /         ---(2) 1:逆波兰表达式的计算规则 从左到右遍历表达式的每个数字和符号,遇到数字就进栈,遇到符号,就将处于栈顶的两个数字出栈,进行运算,再把运算结果进栈,一直到最终获得结果.接下来我们以(2)式为例:

将中缀表达式转换为后缀表达式,然后利用栈对表达式求值。

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="js.js"></script> </head> <body> 输入中缀表达式空格分隔 例如 2 + 3 <input type=

c语言:表达式求值实现(包含加减乘除括号)

这道题不难,但是当你认真去编代码的时候,还是要考虑好多细节,所以不能只停留在看懂的层面上,不去实践你永远不知道你到底掌握了没有,加油! 之前的表达式求值不包括括号运算,现将改进后的代码和源代码粘在上面,便于以后的复习. 一.不包括括号运算 #include<iostream> #include<stdio.h> #include<stdlib.h> #include<string> #include<math.h> #define STACK_I

数据结构算法C语言实现(八)--- 3.2栈的应用举例:迷宫求解与表达式求值

一.简介 迷宫求解:类似图的DFS.具体的算法思路可以参考书上的50.51页,不过书上只说了粗略的算法,实现起来还是有很多细节需要注意.大多数只是给了个抽象的名字,甚至参数类型,返回值也没说的很清楚,所以很多需要自己揣摩.这也体现了算法和程序设计语言的特点,算法更侧重本质的描述,而任何编程语言都要照顾到实现的细节以及数据类型等语法方面的需求. 表达式求值: [编码中....] 二.头文件 迷宫求解: 1 //3_2_maze.h 2 /** 3 author:zhaoyu 4 email:[em

栈的两个应用:括号匹配的检验和表达式求值

1.     括号匹配的检验 假设表达式中含有3种括号:(),[],{},其嵌套的顺序随意.检验括号是否匹配. 基本思想:在算法中设置一个栈,每读入一个括号,若是右括号,则或者与栈顶匹配的左括号相互消解,或者是不合法的情况:若是左括号,则直接压入栈中.若括号匹配,在算法的开始和结束时,栈都应该是空的. 代码: /* * 判断表达式中的括号是否匹配,匹配输出Yes,否则输出No * {(zhang)+[lei]+{lei}={zhangleilei}} -> Yes * {(zhang)+[lei

NYOJ35 表达式求值 【栈】

表达式求值 时间限制:3000 ms  |  内存限制:65535 KB 难度:4 描述 ACM队的mdd想做一个计算器,但是,他要做的不仅仅是一计算一个A+B的计算器,他想实现随便输入一个表达式都能求出它的值的计算器,现在请你帮助他来实现这个计算器吧. 比如输入:"1+2/4=",程序就输出1.50(结果保留两位小数) 输入 第一行输入一个整数n,共有n组测试数据(n<10). 每组测试数据只有一行,是一个长度不超过1000的字符串,表示这个运算式,每个运算式都是以"

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

例三.算术表达式求值 1.问题描述 当一个算术表达式中含有多个运算符,且运算符的优先级不同的情况下,如何才能处理一个算术表达式????? 2.思路 首先我们要知道表达式分为三类:  ①中缀表达式:a+(b-c/d)*e ②前缀表达式+a*-be ③后缀表达式abcd/-e*+ 由于运算符有优先级,所以在计算机中计算一个中缀的表达式非常困难,特别是带括号的更麻烦,而后缀表达式中既无运算符优先又无括号的约束问题因为在后缀表达式中运算符出现的顺序正是计算的顺序,所以计算一个后缀的表达式更简单.所以,可