c++用链栈来实现算术表达式的计算

在我们的日常生活中,对于算术表达式我们更习惯使用操作符在操作数之间的中缀表达式,eg:2+3,但在用计算机实现算术表达式的运算时,考虑到运算效率以即各方面的因素时,将其转化为后缀(3 4 +)或者前缀表达式(+ 3 4)进行处理运算是一种更优的选择。

以下笔者采用后缀表达式来分析“用栈来实现算术表达式的计算”的具体实现过程。

一.实现思想
在进行算术运输时,我们必须要有操作数和操作符,操作数又分为左操作数和右操作数,而操作符也有相应的计算顺序,因此我们考虑用栈来实现这个过程。分别定义一个操作数栈和一个操作符栈来存储算术表达式,并对各操作符设定其优先级,下图为该函数的具体实现过程(在这里我们将运算式看作一个字符串,#一前一后用于判断式子的开始和结尾)。
在这里插入图片描述

二.注意事项
1.操作数出栈时,分为左操作数和右操作数,算得的结果要再次入栈
2.操作符栈内和栈外的优先级不同,而且右括号这个操作符不入栈
3.虑到操作数和操作符两个栈基本相同,对此我们使用模板类对其简化
4.关于find函数:如果查找成功则输出查找到的第一个位置,否则返回-1
5.关于各运算符的优先级。由于在算术运算中各运算符的运算顺序是不相同的,为了量化这样的顺序,我们在这里对其优先级用数字进行量化处理,并且分为栈内优先级和栈外优先级。每当读取一个运算符时,我们将其栈外优先级数值与操作符栈栈顶栈元素优先级进行比较,如果前者大于后者,则说明其紧迫程度高于栈顶元素,该运算符入栈。如果前者栈外优先级数值小于栈顶元素栈内优先级数值,则说明其紧迫程度小于栈顶元素,此时,操作符栈栈顶元素出栈,操作数栈依次弹出两个数作为左操作数和右操作数,运算结果再入操作数栈,然后再进行如上操作。整个过程中我们会发现右括号不会入栈。
在这里插入图片描述

三.实现代码
(linkedstack.h)

#ifndef LINKEDSTACK_H_INCLUDED
#define LINKEDSTACK_H_INCLUDED
//模板类定义一个结点类包含数据域和指针域
template<typename T>
class Node{
public:
  T data;   //数据成员
  Node<T>* next;

  Node(){next = 0 ;}  //无参构造函数初始化
  Node(const T &e){ data = e;next = 0;}  //有参构造函数初始化
};

//模板类定义一个栈
template <typename T>
class LinkStack{
public:
   LinkStack(){head = new Node<T>;}  //无参构造函数
   ~LinkStack();  //析构函数
   
   T& pop(); //出栈
   void push(const T& e );  //入栈
   T& getTop();  //获取栈顶元素
   bool ifEmpty(){return head->next == 0} //判断是否为空栈
private:
   Node<T>* head;
};

#endif

函数实现代码块(linkedstack.cpp)

#include <iostream>
#include <stdlib.h>
#include "linkedStack.h"
using  namespace std;
//析构函数
template<typename T>
LinkStack<T>::~LinkStack()
{
   Node<T>* p = head;
   while(head != 0)
   {
     p = p->next;
     delete(head);
     head = p;      
   }
}

//入栈
template<typename T>
void LinkStack<T>::push(const T& e)
{
    Node<T>* p = new Node<T>(e);  //初始化构造结点p
    p->next = head->next;
    head->next = p;
}

//出栈
template<typename T>
T& LinkStack<T>::pop()
{
    //如果栈为空栈,则程序结束
    if(ifEmpty())
    {
       exit(-1);
    }
    
    Node<T> * p = head->next; 
    static  T e;     //由于要返回栈顶元素,故将其定义为静态变量
    e = p->data;
    head->next = p->next;
    delete(p);
    
    return e;
}

//获取栈顶元素
template<typename T>
T& LinkStack<T>::getTop()
{ 
     //如果栈为空
     if(ifEmpty())
     { 
           exit(-1);
     }
     
     cout << head->next->data <<endl;
}

对表达式进行处理(experss.h)

#ifndef EXPRESSION_H_INCLUDED
#define EXPRESSION_H_INCLUDED
#include <iostream>
using namespace std;

const string OPR = "#(*/+-)";  //运算符列表
const int ISP_TABLE[7] = { 0,1,5,5,3,3,6};  //栈内优先级
const int ICP_TABLE[7] = { 0,6,4,4,2,2,1};  //栈外优先级

int isp(char op);// 返回运算符 op的栈内优先级
int icp(char op);// 返回运算符 op的栈外优先级

int calculate(int lh,int rh, char op);  //运算

//定义一个表达式类
class Expression
{
public:
    Expression(const string& s):exp(s) {} //有参构造函数初始化string
    void disp()
    {
        eval();
        cout << exp << "  = " << result << endl;  
    }
private:
    string exp;
    int result;
    void eval();
};

expression.cpp

#include <sstream>
#include "expression.h"
#include "linkedStack.cpp"

// 返回运算符栈内优先级
inline int isp(char opr)
{
    int idx = OPR.find(opr); //op在运算符表中的下标
    return ISP_TABLE[ idx ];  // 取对应的isp
}

// 返回操作符的栈外优先级
inline int icp(char opr)
{
    return ICP_TABLE[ OPR.find(opr) ];
}

//运算
int calculate(int lh,int rh, char op)
{
    switch(op)
    {
    case '+':
        return lh+rh;
    case '-':
        return lh-rh;
    case '*':
        return lh*rh;
    case '/':
        return lh/rh;
    }
}

void Expression::eval()
{
    //定义一个操作数栈和一个操作符栈,首先#操作符入栈,然后将表达式的结尾加上#字符便于判断
    LinkStack<int>  opnStk;     //操作数栈
    LinkStack<char> oprStk;     //操作符栈
    char ch;
    
    istringstream ist(exp+"#"); //可以实现对一行字符串以空格字符为分隔符进行读取操作
    oprStk.push('#');
    ist >> ch;
    while( !oprStk.ifEmpty() )
    {
        if(isdigit(ch))  //isdigit函数,主要用于检查其参数是否为十进制数字字符   
        {
            opnStk.push(ch-'0');
            ist >> ch;
        }
        else
        {
            if(icp(ch)> isp(oprStk.getTop()))//运算符的栈内优先级与栈外优先级的比较
            {
                oprStk.push(ch);
                ist >> ch;
            }
            else if(icp(ch)<isp(oprStk.getTop()))
            {
                int rh = opnStk.pop(); // left operand
                int lh = opnStk.pop(); // right operand
                int r = calculate(lh,rh,oprStk.pop());
                opnStk.push(r);
            }
            else if(icp(ch) == isp(oprStk.getTop()))
            {
                oprStk.pop();
                ist >> ch;
            }
        }
    }
    result = opnStk.pop();
}

主函数

#include "expression.h"
int main()
{
    Expression e1("2+3*2"), e2("(2+3)*2"),e3("(9-(5-(1+1))*3)"),e4("((6)+((5-1)))/(1+1)"),e5("1");
    
    e1.disp();
    e2.disp();
    e3.disp();
    e4.disp();
    e5.disp();
   
   return 0;
}
发布了10 篇原创文章 · 获赞 2 · 访问量 1143

猜你喜欢

转载自blog.csdn.net/qq_44872260/article/details/102851371