栈的应用——表达式求值

原创 2017年08月23日 16:55:57

概要

表达式求值问题可以说是一个经典问题。具体思路就是首先把输入的中缀表达式转换为后缀表达式,然后再根据后缀表达式进行计算求值。


中缀表达式转换为后缀表达式

首先我们设定运算符在进栈前与进栈后的优先级:
这里写图片描述

  1. 首先在栈把“#”进行压栈,并在中缀表达式追加“#”。“#”作为结束标志。
  2. 对中缀表达式进行遍历,遇到数字进行输出到后缀表达式中
  3. 如果遇到运算符,把栈顶的元素(前者)的栈内优先级与即将入栈元素(后者)的栈外优先级进行比较,如前者小,则运算符入栈,否则,则把栈顶元素(前者)出栈并输出到后缀表达式中,然后把后者入栈。
  4. 循环2,3两步直至中缀表达式的尾部的“#”。

后缀表达式求值

对后缀表达式进行遍历,如果是数字就入栈,如果是运算符,就连续出栈两次的结果进行保存,之后进行相应运算,把运算结果入栈,直至遍历结束,结果为栈顶元素。


下面是具体代码,但是为了减小码量,下面的程序对输入数字有如下要求:必须是0-9的数字,大于等于10不行,即如表达式:(1+(10-5)*2+2)/2是不合法的,10以上的数字不能出现。


#include <iostream>
#include <cstring>
#include <string>
using namespace std;

//这是把中缀表达式转化成后缀表达式的类 
class Transform{
    private:
        char* str;
        int top;
        int size;
    public:
        //表达式求值的构造函数 
        Transform(int size){
            this->size = size;
            str = new char[size];
            top = -1;
        }

        //栈是否为空的函数
        bool IsEmpty(){
            return top == -1;
        }

        //栈是否已满的函数
        bool IsFull(){
            return top == this->size-1;
        }

        //入栈函数
        void Push(char ch){
            if(!this->IsFull()){
                this->str[++top] = ch;  
            }
        }

        //获得栈顶元素 
        char Top(){
            return this->str[top];
        }

        //出栈函数
        void Pop(){
            this->top--;
        } 

        //栈外运算符优先级 
        int icp(char ch){
            int result = 0;
            if(ch == '#'){
                result = 0;
            }
            if(ch == '('){
                result = 6;
            }
            if(ch == '*'||ch == '/'){
                result = 4;
            }
            if(ch == '+'||ch == '-'){
                result = 2;
            }   
            if(ch == ')'){
                result = 1;
            }
            return result;      
        }

        //栈内运算符优先级 
        int isp(char ch){
            int result = 0;
            if(ch == '#'){
                result = 0;
            }
            if(ch == '('){
                result = 1;
            }
            if(ch == '*'||ch == '/'){
                result = 5;
            }
            if(ch == '+'||ch == '-'){
                result = 3;
            }   
            if(ch == ')'){
                result = 6;
            }
            return result;      
        }

        //中缀表达式转为后缀表达式函数
        string Transform_Median(string median){
            //在中缀表达式和栈中追加"#"表示结束 
            median.append("#"); 
            this->Push('#');
            char* c;
            int cnt = 0;
            char* tmp;
            c = new char[median.length()];
            tmp = new char[median.length()];            //后缀表达式的暂存数组 
            strcpy(c,median.c_str());
            for(int i = 0 ; i < median.length() ; i++){
                //如果是数字直接输出到后缀表达式中 
                if(c[i] >= '0' && c[i] <= '9'){
                    tmp[cnt++] = c[i];
                }else{
                    //如果不是数字,则需要和栈顶元素比较运算符优先级 
                    char ch = this->Top();
                    //栈顶元素在栈内的优先级比栈外元素的优先级高,则栈外元素入栈 
                    if(this->isp(ch) < this->icp(c[i])){
                        this->Push(c[i]); 
                    }else if(this->isp(ch) > this->icp(c[i])){
                        //栈顶元素在栈内的优先级比栈外元素的优先级低
                        //则栈内元素出栈,并输出到后缀表达式中,循环变量减1 
                        tmp[cnt++] = ch;
                        this->Pop();
                        i--;
                    }else{
                        //栈顶元素在栈内的优先级等于栈外元素的优先级
                        //说明已经运行到“#”,则出栈即可 
                        this->Pop();    
                    }
                }
            }
            //返回中缀表达式的字符串 
            string after = string(tmp,cnt);
            return after;
        }   
}; 

//这是后缀表达式计算类 
class Sum{
    private:
        int* sum;
        int top;
        int size;
    public:
        //表达式求值的构造函数 
        Sum(int size){
            this->size = size;
            sum = new int[size];
            top = -1;
        }

        //栈是否为空的函数
        bool IsEmpty(){
            return top == -1;
        }

        //栈是否已满的函数
        bool IsFull(){
            return top == this->size-1;
        }

        //入栈函数
        void Push(int num){
            if(!this->IsFull()){
                this->sum[++top] = num; 
            }
        }

        //获得栈顶元素 
        int Top(){
            return this->sum[top];
        }

        //出栈函数
        void Pop(){
            this->top--;
        } 

        //后缀表达式求和
        int Sum_After(string after){
            char* s;
            s = new char[after.length()];
            strcpy(s,after.c_str());
            for(int i = 0 ; i < after.length() ; i++){
                if(s[i] >= '0' && s[i] <= '9'){
                    this->Push(s[i]-'0');
                }else{
                    int b = this->Top();
                    this->Pop();
                    int a = this->Top();
                    this->Pop();
                    int result = 0;
                    switch(s[i]){
                        case '+': result = a + b ;break;
                        case '-': result = a - b ;break;
                        case '*': result = a * b ;break;
                        case '/': result = a / b ;break;
                    };
                    this->Push(result);
                }
            }
            return this->Top();
        } 
};


int main()
{
    string median;
    cout<<"请输入中缀表达式:"<<endl;
    cin>>median;
    Transform transform(median.length());
    string after = transform.Transform_Median(median);
    cout<<"后缀表达式为:"<<endl<<after<<endl;
    Sum sum(after.length()); 
    int result = sum.Sum_After(after);
    cout<<"结果为:"<<endl<<result<<endl; 

    return 0;
 } 

这里写图片描述

版权声明:本文为博主原创文章,未经博主允许不得转载。若需转载,请注明http://blog.csdn.net/qq_30091945 举报

相关文章推荐

堆排序(最小堆)--【算法导论】

堆排序的思想在堆排序(最大堆)已做说明,故不再赘述; 总之,思想就是首先进行建堆,由于这是最小堆,故而必须保证父节点都小于孩子节点,若不满足条件,则进行调节; 最后进行堆排序,不断将最小的提取出来...
  • xjm199
  • xjm199
  • 2014-01-08 21:39
  • 2920

单链表

现在已经进入专业课复习,王道的数据结构复习指导的第一个数据结构虽然是顺序表,但是过于简单,就不想写了。现在复习到链表,首先单链表数其他链表的基础。所以首先把单链表所有基础操作全部写一遍。包括建表,插入...

我是如何成为一名python大咖的?

人生苦短,都说必须python,那么我分享下我是如何从小白成为Python资深开发者的吧。2014年我大学刚毕业..

概念堆是一个用数组表示的完全二叉树,并满足以下两个特性: 1)父节点的键值总是大于或等于(小于等于)其子树上的任意结点 2)每个结点的左子树和右子树都是个堆。 如果父节点的键值总是大于等于任何一...

平衡二叉树

由于平衡二叉树的前提是二叉搜索树,故关于二叉搜索树的内容请移步如下网址:http://blog.csdn.net/qq_30091945/article/details/77720865概念平衡因子:...

并查集

并查集并查集是一种树形结构,又叫“不相交集合”,保持了一组不相交的动态集合,每个集合通过一个代表来识别,代表即集合中的某个成员,通常选择根做这个代表。初始化用数组来建立一个并查集,数组下标代表元素,下...

二叉树的构建及其遍历算法

概要二叉树是一种非常重要的数据结构,很多其他数据机构都是基于二叉树的基础演变过来的。二叉树有先、中、后,层次四种遍历方式,因为树的本身就是用递归定义的,因此采用递归的方法实现三种遍历,不仅代码简洁且容...

二叉搜索树

关于二叉树的基本操作请转到我的另一片博客: http://blog.csdn.net/qq_30091945/article/details/77531651概念Binary Search Tree...

白话经典算法系列之七 堆与堆排序

堆排序与快速排序,归并排序一样都是时间复杂度为O(N*logN)的几种常见排序方法。学习堆排序前,先讲解下什么是数据结构中的二叉堆。二叉堆的定义二叉堆是完全二叉树或者是近似完全二叉树。二叉堆满足二个特...

堆排序(最大堆[1])--【算法导论】

前一章的“概率分析与随机算法”实在伤脑子,好在看过去了,现在正在看的是排序部分; 堆排序,这次说的是最大推排序(和最小堆原理也是相同的),和原文中的思路也是一样的,后序有补充也会贴出来的; 最大堆...
  • xjm199
  • xjm199
  • 2014-01-08 19:23
  • 1737

nyoj 表达式求值--栈的应用

题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=35 题意
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)