使用栈实现表达式求值

看书学了一晚上这个内容,终于实现了

分为三个步骤:

  0. 检查输入是否有误(因为输入其他的非预期字符,程序就会崩溃,我就试着加了一个检查输入的函数)

  1. 先将正常的中缀表达式转换为后缀表达式

  2. 再进行求值

根据后缀表达式求值比较简单,因为后缀表达式已经有了优先级。

比较难懂的是将中缀表达式转换为后缀表达式,需要考虑很多情况:

  1. 如果字符是 ‘(‘ ,就直接入操作符栈,因为越内层的括号优先级越高,所以不用考虑什么

  2. 如果字符是 ‘)‘ ,就要结束一个左括号了,将前面的操作符出栈送入postexp,直到遇到 ‘(‘。

  3. 如果字符是 ‘-‘ 或 ‘+‘ ,就要将遇到的第一个 ‘(‘ 之前的所有操作符出栈送入postexp。因为相对来说,后面的 ‘+‘ 和 ‘-‘ 优先级是最低的,低于前面的所有操作符。最后出栈完,再将它压入栈。

  4. 如果字符是 ‘*‘ 或 ‘/‘ , 先判断前面操作符栈底是否为 ‘*‘ 或 ‘/‘ ,是的话就要将栈里的符号出栈送入postexp。因为 ‘*‘ 或 ‘/‘ 的优先级低于前面的 ‘*‘ 或 ‘/‘,是高于前面的  ‘+‘ 和 ‘-‘  的。

#include <iostream>
using namespace std;
const int MAXSIZE = 50;

typedef struct
{
    char data[MAXSIZE];
    int top;
}Stack;

void InitStack(Stack *&s)
{
    s = (Stack*)malloc(sizeof(Stack));
    s->top = -1;
}

bool Push(Stack *&s, char e)
{
    if (s->top == MAXSIZE - 1)
        return false;
    s->top++;
    s->data[s->top] = e;
    return true;
}

bool Pop(Stack *&s, char &e)
{
    if (s->top == -1)
        return false;
    e = s->data[s->top];
    s->top--;
    return true;
}

bool GetTop(Stack *&s, char &e)
{
    if (s->top == -1)
        return false;
    e = s->data[s->top];
    return true;
}

bool StackEmpty(Stack *&s)
{
    if (s->top == -1)
        return true;
    return false;
}

void trans(char *exp, char postexp[])
{
    int i = 0; // postexp 下标
    char e;    // 给 pop gettop用
    Stack *Optr;
    InitStack(Optr);

    while (*exp != ‘\0‘)
    {
        switch (*exp)
        {
        case ‘(‘:
            Push(Optr, ‘(‘);
            exp++; //exp指针前移,继续处理下一个字符
            break;
        case ‘)‘: //右括号时,一直出栈,指导遇到 (
            Pop(Optr, e);
            while (e != ‘(‘ ) // 当 e=‘(‘ 时,正好把它丢弃了
            {
                postexp[i++] = e;
                Pop(Optr, e);
            }
            exp++;
            break;
        case ‘+‘:
        case ‘-‘: // + - 优先级相同,当做同一种情况处理
            while (!StackEmpty(Optr)) //操作符栈只要不为空,则一直扫描出栈,直到遇到 ) 。
            {
                GetTop(Optr, e);
                if (e == ‘(‘) //后面的 + - ,优先级最低,最后考虑;如果e是 (,则直接入栈即可,所以break
                    break;
                else
                {
                    postexp[i++] = e;
                    Pop(Optr, e);
                }
            }
            Push(Optr, *exp); //最后将 + - 入栈
            exp++;
            break;
        case ‘*‘:
        case ‘/‘:
            while (!StackEmpty(Optr))
            {
                GetTop(Optr, e);
                if (e == ‘/‘ || e == ‘*‘) // * / 的优先级仅仅低于它前面的 * /,高于前面的 + -,所以要将前面的 * / 弹出栈;+ - 保留,因为新的 * / 会放在栈低,优先级高。
                {
                    postexp[i++] = e;
                    Pop(Optr, e);
                }
                else
                    break; // 其他情况( + - 左括号 )退出,
            }
            Push(Optr, *exp); //最后将 / * 入栈
            exp++;
            break;
        default:
            while (*exp > ‘0‘ && *exp < ‘9‘) //循环判断是否为数字字符,如果是则保存到postexp,循环判断是因为可能是多位数字
            {
                postexp[i++] = *exp;
                exp++;
            }
            postexp[i++] = ‘#‘; //以#标志一个数字字串结束
        }
    }
    while (!StackEmpty(Optr)) //扫描完exp后,操作符栈可能还有操作符,将其存到postexp
    {
        Pop(Optr, e);
        postexp[i++] = e;
    }
    postexp[i] = ‘\0‘; //结束字符串
    free(Optr); //销毁栈
}

//--------- 下面是针对数字型栈的

typedef struct
{
    double data[MAXSIZE];
    int top;
}Stack_num;

void InitStack_num(Stack_num *&s)
{
    s = (Stack_num *)malloc(sizeof(Stack_num));
    s->top = -1;
}

bool Push_num(Stack_num *&s, double e)
{
    if (s->top == MAXSIZE - 1)
        return false;
    s->top++;
    s->data[s->top] = e;
    return true;
}

bool Pop_num(Stack_num *&s, double &e)
{
    if (s->top == -1)
        return false;
    e = s->data[s->top];
    s->top--;
    return true;
}

//---------

double compvalue(char *postexp)
{
    Stack_num *num; //操作数栈
    InitStack_num(num);
    double result; //结果
    double a, b; //弹出栈的两个数
    double c; //计算弹出栈的两个数
    double d;    //将连续的数字字符转换成整数保存在d里
    while (*postexp != ‘\0‘)
    {
        switch (*postexp)
        {
        case ‘+‘:
            Pop_num(num, a); //因为后缀表达式已经有了优先级了,所以可以直接弹出两个数进行计算
            Pop_num(num, b);
            c = a + b;
            Push_num(num, c);
            break;
        case ‘-‘:
            Pop_num(num, a);
            Pop_num(num, b);
            c = b - a; //注意是b-a,因为a先出来,是后面的数字
            Push_num(num, c);
            break;
        case ‘*‘:
            Pop_num(num, a);
            Pop_num(num, b);
            c = a * b;
            Push_num(num, c);
            break;
        case ‘/‘:
            Pop_num(num, a); // a是除数
            Pop_num(num, b);
            if (a != 0)
            {
                c = b / a;
                Push_num(num, c);
            }
            else
            {
                cout << "除0错误!" << endl;
                exit(0);
            }
            break;
        default:
            d = 0;
            while (*postexp >= ‘0‘ && *postexp <= ‘9‘) //当 *postexp = # 时,就忽略了。
            {
                d = 10 * d + (*postexp - ‘0‘);
                postexp++;
            }
            Push_num(num, d);
        }
        postexp++; //继续下一个字符
    }
    Pop_num(num, result);

    return result;
}

bool test(char *exp)
{
    // start - 是否非法字符
    for (int i = 0; exp[i] != ‘\0‘; i++)
    {
        if ( !((exp[i] >= ‘0‘ && exp[i] <= ‘9‘) || exp[i] == ‘+‘ || exp[i] == ‘-‘ ||             exp[i] == ‘*‘ || exp[i] == ‘/‘ || exp[i] == ‘(‘ || exp[i] == ‘)‘) )

            return false;
    }
    // end - 是否非法字符

    // start - 括号是否匹配
    Stack *s;
    char e;
    InitStack(s);
    for (int i = 0; exp[i] != ‘\0‘; i++)
    {
        switch (exp[i])
        {
        case ‘(‘:
            Push(s, exp[i]);
            break;
        case ‘)‘:
            if (Pop(s, e))
            {
                if (exp[i] == ‘)‘ && e == ‘(‘)
                    return true;
                else
                    return false;
            }
            else
                return false;
            break;
        }
    }
    if (s->top != -1)  //栈为空才认为成功
        return false;
    else
        return true;

    // end - 括号匹配

    return true;
}

int main()
{
    char exp[MAXSIZE];
    char postexp[MAXSIZE];

    while (true)
    {
        cout << "输入表达式:";

        cin >> exp;
        if (!test(exp))
        {
            cout << "非法字符 或 括号不匹配!" << endl;
            continue;
        }
        trans(exp, postexp);

        cout << "后缀表达式:" << postexp << endl;
        cout << "结果:" << compvalue(postexp) << endl;
    }

    system("pause");
    return 0;
}

  

原文地址:https://www.cnblogs.com/bin21st/p/9827621.html

时间: 2024-10-16 22:15:08

使用栈实现表达式求值的相关文章

Dijkstra的双栈算术表达式求值

import java.util.Stack; import java.util.Scanner; public class Evaluate { public static void main(String[] args) { Stack<String> ops=new Stack<String>(); Stack<Double> vals=new Stack<Double>(); Scanner cin=new Scanner(System.in); /

栈实现表达式求值

本文简单的设计了一个针对一位整数的四则运算进行求值的算法,对于处理多位整数的四则运算,需要对本文接受输入的数据类型进行升级,把字符数组换成字符串数组,将一个整数的多位数字存入一个字符串进行处理. 代码如下: 1 //用栈实现表达式求值(简化版) 2 #include<iostream> 3 #include<string> 4 #include<cassert> 5 using namespace std; 6 //栈的基本操作的实现 7 template<typ

算法手记(2)Dijkstra双栈算术表达式求值算法

这两天看到的内容是关于栈和队列,在栈的模块发现了Dijkstra双栈算术表达式求值算法,可以用来实现计算器类型的app. 编程语言系统一般都内置了对算术表达式的处理,但是他们是如何在内部实现的呢?为了了解这个过程,我们可以自行搭建一套简易的算术表达式处理机制,这里就用到栈特性和本篇提到的Dijkstra算法. 概述:     算术表达式可能是一个数.或者是由一个左括号.一个算术表达式.一个运算符.另一个算术表达式和一个右括号组成的表达式.为了简化问题,这里定义的是未省略括号的算术表达式,它明确地

栈应用—表达式求值

#include<stdio.h> #include<stdlib.h> #define LENGTH 100 //初始分配栈的长度 #define ADD_LEN 10 //栈长增量 typedef struct //定义字符栈 { int *base; int *top; int stacksize; }SqStack; void InitStack(SqStack &S); //初始化一个栈 void Push(SqStack &S,int e); //e进入

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

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

Dijkstra的双栈算术表达式求值算法 C++实现

1 #include<iostream> 2 #include<string> 3 using namespace std; 4 5 template<typename T> 6 class Stack 7 { 8 private: 9 T stack[100]; 10 int i = 0; 11 public: 12 Stack() = default; 13 14 T pop() 15 { 16 if (i == -1) 17 { 18 cout <<

栈练习--Dijkstra的双栈算术表达式求值算法

此法还有待完善,比如在做除法运算时未判断除数是否为0,而且也可以加以扩展,比如log.sin.操作符优先级.. 1 public class Evaluate { 2 3 public static void main(String[] args) { 4 String steam = "( 1 + ( 2 + 3 ) * ( 4 * 5 ) ) )"; 5 // String steam = "( ( 1 + sqrt ( 5.0 ) ) / 2.0 )"; 6

栈在表达式求值中的应用

将中缀表达式转成后缀表达式. #include<iostream> #include <stack> #include<map> #include <math.h> #include <stdlib.h> #include <string.h> #include <stdio.h> using namespace std; //把中缀表达式转化为后缀表达式 a+b-a*((c+d)/e-f)+g# 1+2-3*((4+5)

Dijkstra的双栈算术表达式求值算法

1 public static double evaluate(String inStr) { 2 Stack<String> ops = new Stack<String>(); //操作符栈 3 Stack<Double> vals = new Stack<Double>(); //操作数栈 4 char[] arr = inStr.toCharArray(); 5 for(char c : arr){ 6 String s =c+""