数据结构与算法学习 C++ | <001> 表达式求值问题(基础&&拓展)

611 阅读15分钟

hello world.jfif

1. 数据结构与算法 -- 开端

Niklaus Wirth提出过一个著名的公式:

程序 = 数据结构 + 算法

----所谓程序,即用于控制计算机的工作流程,完成指定的逻辑功能,最终实现某种任务的指令。而数据结构,以书本的画来说,就是现实世界的数据及其间关系的反映。至于算法,则是程序的逻辑抽象,是解决某类客观问题的流程。

----我们深知,人们能够利用计算机解决实际的问题。为了贴合计算机的基本技术需求,我们需要对目标建立模型,然后确定恰当的数据结构表示该模型,并且以此为基础,设计合适的计算方法。最终,满足我们解决问题的最终需求。

----综上所述,我们引入第一个实际问题:

1.1 程序栈(Stack)

----栈是一种具有特殊运算要求的线性表,其仅能在表尾进行插入和删除操作。在这种条件下,我们把表尾称为栈顶 Top,表头称为栈底 Base。总结起来,它的特性如下:

  1. 栈限定只能于表的端点进行插入与删除。
  2. 栈具有后进先出的特性,即LIFO(Last in first out)
  3. 插入元素到栈顶(表尾)的操作,即入栈。
  4. 从栈顶(表尾)删除最后一个元素的操作,即出栈。
  5. 入栈出栈均可以随时进行。

image.png

1.2 表达式求值 -- 问题分析

----在设计方案之前,我们要先对表达式的组成做一个分析。它分为三个主要部分:第一个部分是操作数(Operand),通常由常数和变量组成。第二个部分是运算符(Operator),主要划分为算术运算符、关系运算符和逻辑运算符。第三个部分是界限符(Delimiter),核心为左右括弧和表达式结束符。我们知道,任何一个算术表达式都包括操作数、算术运算符和界限符构成,因此,解决问题的核心就在于:如何表达这三个部分,并找出它们的优先级次序。

----确定了主要方向之后,我们就要着手开始构造算法。根据各类资料,我们选取由“运算符优先级确定运算顺序的表达式求值算法”,即算符优先算法。该算法可以使用两个工作栈,一个设为 Operator,用于寄存运算符。一个设为 Operand,用于寄存操作数和运算结果。考虑到我是以“上机实验”作为主要设计目标的,所以基础操作不引入 Stack,一切以完整程序设计为准。

----梳理一下任务,我们任务目标是以下几点:

  1. 构造函数 In(C):判断 C 是否为运算符。
  2. 构造函数 Precede (number1,number2):判断运算符 number1、number2 优先级。
  3. 构造函数 Operate (a,theta,b):对 a 和 b 进行二元运算 theta。

----任务基础标准是算术基本准则:

  1. 我们必须遵守“先乘除、后加减”的原则。
  2. 我们要选择从左至右进行计算。
  3. 我们要先计算括号内的表达式,再计算括号外的表达式。 image.png
1.3 表达式求值 -- 进一步剖析

----我们知道,算符之前存在优先级关系。但是,单独考虑任何一种算符,都会造成程序设计上的混乱。基于这个问题,我依照资料提示,绘制了一张表格,以基础的四则运算作为基础,表述了其先后关系。其中,“>”为高优先级,“<”为低优先级,“=”为相同优先级。

image.png

----对于本问题的解决计划也就随之产生了:

第一步、 我们要设定两个栈:

  1. OPND -- 代表操作数和运算结果

  2. OPTR -- 代表运算符 第二步、 我们要初始化 OPTR 和 OPND ,将表达式起始符“#”压入 OPTR 。紧接着,我们扫描表达式,读入第一个字符 ch ,如果表达式没有扫描完毕至“#”或者 OPTR 的栈顶元素不为“#”时,则循环如下操作:

  3. 如若 ch 不是运算符,则压入 OPND ,读入下一个字符 ch 。

  4. 如若 ch 是运算符,则根据 OPTR 的栈顶元素和 ch 的优先级比较结果,做出不同的处理。

第三步,对于具体的处理方式,我们给出如下解释:

  1. 如果是“小于”,则 ch 压入 OPTR, 读出下一个字符 ch
  2. 如果是“大于”,则弹出 OPTR 栈顶的运算符,从 OPND 栈弹出两个数,进行对应的运算,结果再压入 OPND 。
  3. 如果是“等于”,则 OPTR的栈顶元素是 “(” 而且 ch 是“)”,此时弹出 OPTR 栈顶的“(”,相当于括号匹配完成,读下一个字符 ch 。

----最终 OPND 栈顶元素就是表达式求值的结果,返回此元素即可。我们用表格再次对以上的计划进行一次分析。

image.png

1.4 表达式求值 -- 基础四则运算的代码解析

----根据各类资料以及我自己的思考,我决定先创建一个栈的基本构架,然后逐步实现函数 In 、Percede 、Operate,最终按照示例之中的运算表述过程完善程序编写。(注意:我谨以学习目的,参考了大量有关问题的代码资料,因此本代码虽然是我自己独自键入的,但是仅作参考)

代码如下:

第一步,我尝试使用了结构体,构造了基本的栈(Sqstack)

//引入库文件
#include <iostream>
#include "WriteStack.h"
#include<cmath>
#include <string>
#include <algorithm>
#include<stdlib.h>
#include<vector
//以下为需要定义的常量
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define OVERFLOW -2
#define MAXSIZE 10000000

//设置一些特殊变量
using namespace std;
typedef char SElemType;
typedef int NElemType;
typedef int Status;

第二步,我尝试初始化运算符栈和操作数栈,并且创造最基本的功能。最开始的部分,我希望通过使用结构体,构造出运算符栈和操作数栈,并且赋予它们入栈、出栈、栈满提示、取栈顶元素等几项能力,方便我们进行下一步的计算。(其间,我把运算符栈称之为 S型,把操作数栈称之为 N型)

//我们开始定义结构体类型
typedef struct {
    SElemType *base;
    SElemType *top;
    int stacksize;
}SqStack_optr; //运算符栈类型

typedef struct {
    NElemType *base;
    NElemType *top;
    int stacksize;
}SqStack_opnd;//操作数栈类型

//我们给一个初始化的函数构造(运算符栈初始化)
Status InitStackS ( SqStack_optr &S )
{
    S.base = new SElemType[MAXSIZE];  
    //新建连续存储空间:类型确定为SElemType, 其大小为 MAXSIZE(10000) 然后赋值给栈底指针 
    if (!S.base)
    return OVERFLOW; 
    //分配失败返回 -2
    S.top = S.base; 
    //把base栈底指针的地址也赋值给栈顶指针
    S.stacksize = MAXSIZE; 
     //赋值栈的容量
    return OK;
}

//我们给一个初始化的函数构造(操作数栈初始化)
Status InitStackN ( SqStack_opnd &S )
{
    S.base = new NElemType[MAXSIZE];  
    //新建连续存储空间:类型确定为SElemType, 其大小为 MAXSIZE(10000) 然后赋值给栈底指针 
    if (!S.base)
    return OVERFLOW; 
    //分配失败返回 -2
    S.top = S.base; 
    //把base栈底指针的地址也赋值给栈顶指针
    S.stacksize = MAXSIZE;  //赋值栈的容量
    return OK;
}

//运算符插入操作
Status PushS( SqStack_optr &S, SElemType e)
{
     if( S.top - S.base == S.stacksize ) //栈满
        return ERROR;
        *S.top ++ = e;
        return OK;
}

//操作数插入操作
Status PushN( SqStack_opnd &S, NElemType e)
{
     if( S.top - S.base == S.stacksize ) //栈满
        return ERROR;
        *S.top ++ = e;
        return OK;
}

//运算符栈出栈操作
Status PopS( SqStack_optr &S, SElemType &e)
{
     if( S.top == S.base ) // 栈变空
       return ERROR;
       e= *--S.top;
       return OK;
}

//操作数栈出栈操作
Status PopN( SqStack_opnd &S, NElemType &e)
{
     if( S.top == S.base ) // 栈变空
       return ERROR;
       e= *--S.top;
       return OK;
}

//运算符栈取栈顶元素
Status GetTopS( SqStack_optr S)
{
    SElemType e;
    if(S.top==S.base)
    return ERROR;
    e=*(S.top-1);
    return e;
}

//操作数栈取栈顶元素
Status GetTopN( SqStack_opnd S)
{
    NElemType e;
    if(S.top==S.base)
    return ERROR;
    e=*(S.top-1);
    return e;
}

第三步,我们要开始准备判断目标字符,如果该字符属于运算符,就返回 TRUE。如果该字符不属于运算符,就返回 FALSE。在此处,我们加入了第一个扩展内容,即取余运算。通过细心观察不难发现,取余运算和乘除运算是没有区别的,他们的优先级没有先后之分,两个符号也不会紧挨在一起。 由此,我们可以直接插入取余运算的功能项,完成之后的代码。

//判断 字符c 是否为运算符,如果是运算符,那么返回TRUE。如果不是运算符,那么返回FALSE
Status In(SElemType c)//应在前面有定义 typedef char SElemType
{
    switch(c)
    {   //逐个判断其是否为运算符
        case '+':return TRUE;
        case '-':return TRUE;
        case '*':return TRUE;
        case '/':return TRUE;
        case '%':return TRUE;
        case '(':return TRUE;
        case ')':return TRUE;
        case '#':return TRUE;
        default: return FALSE;
    }
}

//判断运算符的优先级,如果 运算符1 大于 运算符2, OPND出栈,运算符1出栈,完成运算后压栈OPND
//如果 运算符1 小于 运算符2, 运算符2压栈
//如果 运算符1 等于 运算符2,脱括号
SElemType Precede(SElemType t1,SElemType t2)
{  //细心观察其优先级顺序
   SElemType f;
   switch (t2)
   {
   case '+': if(t1=='('||t1=='#')
              f='<';
             else
              f='>';
            break;

   case '-': if(t1=='('||t1=='#')
              f='<';
             else
              f='>';
            break;

    case '*': if(t1=='('||t1=='#'||t1=='+'||t1=='-')
              f='<';
             else
              f='>';
            break;
    case '/': if(t1=='('||t1=='#'||t1=='+'||t1=='-')
              f='<';
             else
              f='>';
            break;
    case '%': if(t1=='('||t1=='#'||t1=='+'||t1=='-')
              f='<';
             else
              f='>';
            break;
  
    case '(': if(t1=='=')
              f='=';
             else
              f='<';
            break;   

    case ')': if(t1=='('||t1=='#')
              f='=';
             else
              f='>';
            break;   

    case '#': if(t1=='('||t1=='#')
              f='=';
             else
              f='>';
            break;          
   }
return f;
}

//
NElemType Operate(NElemType a,SElemType theta,NElemType b)
{
    NElemType c;
    switch(theta)
    {
        case '+':
        c=a+b;
        break;

        case '-':
        c=a-b;
        break;

        case '*':
        c=a*b;
        break;

        case '/':
        c=a/b;
        break;   

        case '%':
        c=a%b;
        break;           
    }
    return c;
}

第四步,也就是核心部分,我们要编写个位数限制的运算程序。在函数之中,我们要定义出 OPND 和 OPTR,按照上文的设计方案,对二者进行初始化,并且对输入的合法运算表达式进行压入(Push)、计算(Operate)、出栈(Pop)。

//主要运算用的程序(个位数)
int EvaluateExpressionOne(){

    SqStack_opnd OPND;
    SqStack_optr OPTR;

    int a,b;
    char ch,x,theta;
    InitStackS(OPTR);
    PushS(OPTR,'#');
    InitStackN(OPND);
    cin>>ch;
    while(ch!='#'||GetTopS(OPTR) != '#')
    {
        if(!In(ch))
        {
          PushN(OPND,ch-'0');
          cin>>ch;
        }             //如果ch不是运算符,则让其进栈
        else
            switch (Precede(GetTopS(OPTR),ch))  //我们来开始比较优先权
            {
                case '<':      //当前字符ch压入OPTR栈,读入下一字符ch
                PushS(OPTR,ch);
                cin>>ch;
                break;

                case '>':      //弹出OPTR栈顶的运算符运算,并将运算结果入栈
                PopS(OPTR,theta);
                PopN(OPND,b);
                PopN(OPND,a);
                PushN(OPND,Operate(a,theta,b));
                break;

                case '=':      //脱括号并开始接受下一个字符的信息
                PopS(OPTR,x);
                cin>>ch;
                break;
            }
           
    } return GetTopN(OPND);
}

----到这里,表达式求值问题的基础部分就完成了。现在,如果我在主程序之中调用上述函数,就能够完成最基本的“加、减、乘、除、取余”几项计算。(仅限于个位数,且运算式必须合法)

2. 有趣的拓展内容 -- 进阶

----在编写程序时,我注意到了几个很有意思的点。首先,假若我们需要十位数以上的运算单位,那该怎么解决呢?其次,假若我们需要存在小数的运算过程,那该如何实现呢?紧接着,如果我们需要使用逻辑运算关系,那该如何改造代码呢?最后,如果我们需要添加负数运算,那该如何编写新函数呢?综合以上问题,我们开始逐一解决。

161646vpyh2j01t2mgzjzd.png

2.1 表达式求值 -- 拓展表达式求值的代码解析

----本质上,如果需要十位数以上的运算单位,其原理与个位数差别不大,我们可以引入一个判断数,用于对比上次读取的是否是数字的标志位置,初始设为 0,遇到数字改为 1,遇到字符改为 0。

代码如下:

//主要运算用的程序(多位数)
int EvaluateExpressionPlural(){

    SqStack_opnd OPND;
    SqStack_optr OPTR;

    int a,b,t,e;
    char ch,x,theta;
    InitStackS(OPTR);
    PushS(OPTR,'#');
    InitStackN(OPND);
    cin>>ch;
    int isnum=0;    //对位数进行判断
    while(ch!='#'||GetTopS(OPTR) != '#')
    {
        if(!In(ch))
        {
            if(isnum==1)
            {
               PopN(OPND,e);
               t=ch-'0';
               PushN(OPND,e*10+t);
               isnum=1;
            cin>>ch;
            }
            else{
          PushN(OPND,ch-'0');
          isnum=1;
          cin>>ch;
          }
        }             //如果ch不是运算符,则让其进栈
        else
        {
            isnum=0;
        
            switch (Precede(GetTopS(OPTR),ch))  //我们来开始比较优先权
            {
                case '<':      //当前字符ch压入OPTR栈,读入下一字符ch
                PushS(OPTR,ch);
                cin>>ch;
                break;

                case '>':      //弹出OPTR栈顶的运算符运算,并将运算结果入栈
                PopS(OPTR,theta);
                PopN(OPND,b);
                PopN(OPND,a);
                PushN(OPND,Operate(a,theta,b));
                break;

                case '=':      //脱括号并开始接受下一个字符的信息
                PopS(OPTR,x);
                cin>>ch;
                break;
            }
        } //else
    } return GetTopN(OPND);
}

以上代码有几个变量需要注意:

  1. InitStackS(OPTR) 这个函数的用处是初始化一个运算符栈,并将“#”压入栈底以便最终判断表达式是否完成。
  2. InitStackN(OPND) 这个函数的用处是初始化一个操作数栈,存放数字以及中间的运算结果。
  3. t = ch-'0' 执行这个操作的原因是 ch 为字符类型的数字,所以将其转化为真正的数时,需要减掉 0 的ASCII编码差值。

----同理,在处理小数运算时,我们也可以很容易就明确要做的目标。为了更有意思一些,我通过查询资料找到了一种利用二维数组的代码比较方法,重新定义了 Precede() 。由于操作数和运算符都只能用字符型来输入,我们得用 ASCII 编码实现区分。那就先从写出 “stack.h” 开始(懒癌发作)。

具体代码如下:

#ifndef _WIRTE_STACK_H_
#define _WIRTE_STACK_H_

#include<iostream>
#include<stdlib.h>
using namespace std;

#define MAXSIZE 10000000
template<class type>
class Write_stack
{
    int top;
    type* my_s;
    int maxsize;

public:
    Write_stack():top(-1),maxsize(MAXSIZE)
    {
        my_s=new type[maxsize];
        if(my_s==NULL)
        {
            cerr<<"分配失败"<<endl;
            exit(1);
        }
    }
    Write_stack(int size):top(-1),maxsize(size)
    {
        my_s=new type[maxsize];
        if(my_s==NULL)
        {
            cerr<<"分配失败"<<endl;
            exit(1);
        }
    }
    ~Write_stack()
    {
        delete[] my_s;
    }
    //检查栈是不是空的
    bool Empty();
    //压入
    void Push(type tp);
    //返回栈顶
    type Top();
    //出栈
    void Pop();
    //栈的大小
    int Size();
};

template<class type>
bool Write_stack<type>::Empty()
{
    if(top==-1){
        return true;
    }
    else
        return false;
}

template<class type>
type Write_stack<type>::Top()
{
    if(top != -1)
    {
        return my_s[top];
    }
    else
    {
        cout<<"这个栈她变空了!!\n";
        exit(1);
    }
}

template<class type>
void Write_stack<type>::Push(type tp)
{
    if(top+1<maxsize)
    {
        my_s[++top]=tp;
    }
    else
    {
        cout<<"栈满\n";
        exit(1);
    }
}

template<class type>
void Write_stack<type>::Pop()
{
    if(top>=0)
    {
        top--;
    }
    else
    {
        cout<<"栈空\n";
        exit(1);
    }
}

template<class type>
int Write_stack<type>::Size()
{
    return top+1;
}

#endif

----我在编辑这部分代码时,出现了 redefinition 故障。这个问题在于,include 指令把”.h"文件的内容在”.h"文件之前展开,如果没有条件编译语句,程序会重复引用和循环递归 include 指令。解决方案非常简单,只要在上下代码部分加入:

#ifndef _Aim_H_ 
#define _Aim_H_ //两者一致 
class Aim { ....... }; 
#endif 

----问题就会迎刃而解。(亲测有效,救命)

//这是为小数计算准备的新方法
Write_stack<char>OPTR_new;
Write_stack<double>OPND_new;

typedef struct 
{//输入表达式时,操作数若长度大于 2 无法正确得到操作数
 char data[10];
 int length;
}NumberSaving;
bool In_new(char ch)//判断输入的是不是运算符,若是则返回true
{
 if (ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '(' || ch == ')'||ch=='#')
 {
  return true;
 }
 else return false;
}

char Precede_new(char x, char y)//运算符优先级的判断
{
 int Square[2];
 char opnd[2] = { x,y };
 char data_data[7][7] = {
     {'>','>','<','<','<','>','>'},
     {'>','>','<','<','<','>','>'},
     {'>','>','>','>','<','>','>'},
     {'>','>','>','>','<','>','>'},
     {'<','<','<','<','<','=',' '},
     {'>','>','>','>',' ','>','>'},
     {'<','<','<','<','<',' ','='}
 };
 for (int count = 0; count < 2; count++)
 {
  switch (opnd[count])
  {
  case '+':Square[count] = 0;
   break;
  case '-':Square[count] = 1;
   break;
  case '*':Square[count] = 2;
   break;
  case '/':Square[count] = 3;
   break;
  case '(':Square[count] = 4;
   break;
  case ')':Square[count] = 5;
   break;
  case '#':Square[count] = 6;
   break;
  }
     }
 return data_data[Square[0]][Square[1]];
}
double Operate_new(double a, char theta, double b)//加、减、乘、除运算
{
 double result;
 switch (theta)
 {
 case '+': result=a + b;
       break;
 case '-':result= a - b;
       break;
 case '*':result= a * b;
       break;
 case '/':result= a / b;
       break;
  }
 return result ;
}
double CharForNum(NumberSaving NumSave)//字符数字转换成完整的数字型数字
{
 int point=0;//用来判断小数点的位置
 double result=0;
 
 for (int i = 0; i < NumSave.length; i++)//先找出小数点的具体位置
 {
  if (NumSave.data[i] == '.')
   break;
     ++point;
    }
 for (int i=0,j = 0; i < NumSave.length; i++)//转换数字
 {
  if (i != point)//小数点不放入计算
  {
   result += (NumSave.data[i] - '0')*pow(10, point - j - 1);
   j++;
  }
 }
 return result;
}
double EvaluateExpressionPoint()
{
 bool judge = true;//用来判断是否输入了一个数字。输入完成就让其转化为数字型,存入栈中
 NumberSaving NumSave;//用来记录字符,转换为数字
 OPTR_new.Push('#');//将表达式起始符压入栈中,用于进行判断
 char ch,theta;//记录
 int i=0;
 double a, b;//记录
 cout<<"请输入需要计算的表达式,以'#'结束"<<endl;
 cin >> ch;
 NumSave.length = 0;
 while (ch != '#' || OPTR_new.Top() != '#')// ch=='#'并不能停止循环
 {
  if (!In_new(ch))
  {
    NumSave.data[i] = ch;
    ++i;
    ++NumSave.length;
    judge = true;
    cin >> ch;
  }
  else {
   if (judge)//思路:即当输入运算符时,表明运算符的前一个操作数已经输入完毕
             //此时可以将结构存储的数字字符转换成double型,并将数字进入OPND栈
   {
    OPND_new.Push(CharForNum(NumSave));//字符转换数字
    NumSave.length = 0; i = 0;//所有回到初始化,用以记录下一个数字
    judge = false;//操作数进栈成功后必须将flag取反。
                  //若进行case '>'时,ch还需再次进入while循环
                  //进而判断ch与OPTR栈顶操作符,比较优先级
                  //因为ch还需进入while循环,所以在此之前要把 flag=false,
                  //若flag=true不再改变,这时数字0进栈,导致运算出错
   }
   switch (Precede_new(OPTR_new.Top(), ch))
   {
       case '>': { 
           theta = OPTR_new.Top();
           OPTR_new.Pop();  //取OPND栈顶两个数以及OPTR栈顶运算符进行运算,结果再入栈
                   
                   b= OPND_new.Top(); 
                   OPND_new.Pop();
                  
                   a= OPND_new.Top(); 
                   OPND_new.Pop();
                   
                   OPND_new.Push(Operate_new(a, theta, b));
                   break;
               }
       case '<': {
        OPTR_new.Push(ch);
        cin >> ch;
        break;
             }
       case '=': {
        OPTR_new.Pop();
        cin >> ch;
        break;
              }
        }
    }
 }
 return OPND_new.Top();
}

2.2 表达式求值 -- 逻辑运算问题

----上述代码完整实现了小数运算,借此,我们可以开始思考逻辑运算到底如何实现。顾名思义,代码组合需要尝试引入逻辑或、逻辑与、逻辑非的相关运算。虽然运算内容改变了,但是运算规律依旧可以被上文的基础方法纵向剖析。我尝试画出了一张表格,用来描述逻辑运算的先后顺序(如下图所示)。

image.png

根据图片之中所示的关系,我组织的代码如下:

string charactor;
char symbol[6] = { '!','&','|','(',')','#' };
char order[6][6] =
{
	'>', '>', '>', '<', '>', '>',
	'<', '>', '>', '<', '>', '>',
	'<', '<', '>', '<', '>', '>',
	'<', '<', '<', '<', '=', '>',
	'>', '>', '>', '<', '>', '>',
	'<', '<', '<', '<', '>', '=',
};

int findsetting(char option)
{
	for (int i = 0; i < 6; i++)
	{
		if (symbol[i] == option)
			return i;
	}
}

char compare(char a, char b)
{
	int x = findsetting(a);
	int y = findsetting(b);
	return order[x][y];
}

int calculator(int x, int y, char option)
{
	if (option == '|')
		return x | y;
	if (option == '&')
		return x&y;
	return 0;
}

int EvaluateExpressionLogic()
{
    getchar ();
     while (getline(cin, charactor))
	{
		int lens = charactor.size();
		charactor += "#"; 
		charactor += '\0';
		int t, x, y;
		char option;
		int i = 0;
		Write_stack<int>P;
		Write_stack<char>Q;
		Q.Push('#');   //末尾符号“#”
		while (charactor[i] != '#' || Q.Top() != '#')
		{
			if (charactor[i] == '1' || charactor[i] == '0')
		{
		if (charactor[i] == '1')
		t = 1;
		else
		t = 0;
		P.Push(t);//遇到数字就往P里放
		i++;
		}
			else if (charactor[i] != ' ')//输入可包含空格,略过空格
			{
		switch (compare(Q.Top(), charactor[i]))//若是运算符则和Q栈的栈顶运算符比较优先级
		{
        case '<':  // 栈顶元素优先级低,则当前元素入栈
		Q.Push(charactor[i]);
		i++;
		break;
		case '=': //当一对括号相遇时表示括号内已运算完成,脱括号并接收下一字符
		Q.Pop();
		i++;
		break;
        case '>':  // 退栈并将运算结果入栈
		if (Q.Top() == '!')
            {   // 栈顶元素->!
			x = P.Top();
			P.Pop();
			P.Push(!x);
			Q.Pop();
			}
			else
            {   // 栈顶元素非!
			x = P.Top();
			P.Pop();
			y = P.Top();
			P.Pop();
			option = Q.Top();
			Q.Pop(); //计算结果并入栈
			P.Push(calculator(x, y, option));
			}
			break;
				}
			}
		}
		int target = P.Top();
		cout << target;
	}
    return 0;
}

----逻辑运算的难度实际上并不如小数运算高。因为其只需要考虑左右计算顺序和括号即可,甚至不存在复杂的计算关系,数字上也不会过于麻烦。所以相较于下文的内容,逻辑运算的扩展可以说是比较友好的。

2.3 表达式求值 -- 负数运算问题

----负数运算需要牵扯的东西太多了。第一点,考虑到负数打乱了符号位置的规律,只通过栈的知识很难完全处理运算过程,因为两种同类型的符号会在放在一起,不能通过单一的判断来完成运算。第二点,负数运算需要用容器(vector),新的数据处理方式也会给整体制造难度。第三点,负数运算需要将中缀表达式换算成后缀表达式,方便计算。这件事可以用二叉树实现,但是我们也能依靠栈和容器的知识来完成。

具体代码如下:

string format(string str_one){
	for(int i = 0;i < str_one.length(); i++){
		if(str_one[i] == '-')
        {
			if(i == 0)
            {
				str_one.insert(0,1,'0');
			}else if(str_one[i-1] == '('){
				str_one.insert(i,1,'0');
			}
		}
		
	}
	return str_one;
}
int orderone(char c){
	if(c == '+' || c == '-'){
		return 1;
	}else if(c == '*' || c == '/'){
		return 2;
	}else{
		return 0;
	}
	
} 
vector<string> horizon(string str_one){
	vector<string> visual;
	Write_stack<char> Des_one;
	for(int i = 0;i < str_one.length(); i++){
		string tmp = "";
		switch(str_one[i]){
			case '+':
			case '-':
			case '*':
			case '/':
				if(Des_one.Empty() || Des_one.Top() == '('){
					Des_one.Push(str_one[i]);
				}else{
					while(!Des_one.Empty() && orderone(Des_one.Top()) >= orderone(str_one[i]) ){
						tmp += Des_one.Top();
						visual.push_back(tmp);
						Des_one.Pop();
						tmp = "";
					}
					Des_one.Push(str_one[i]);
				}
				break;
			case '(':
				Des_one.Push(str_one[i]);
				break;
			case ')':
				while(Des_one.Top() != '('){
					tmp += Des_one.Top();
					visual.push_back(tmp);
					Des_one.Pop();
					tmp = "";
				}
				Des_one.Pop();
				break;
			default:
			if((str_one[i]>='0' && str_one[i]<='9')){
            	tmp += str_one[i];
            	while(i+1<str_one.size() && str_one[i+1]>='0' && str_one[i+1]<='9'||str_one[i+1] == '.')
            	{
                	tmp += str_one[i+1];
                	++i;
   				}
            	visual.push_back(tmp);
  			}
		}
	}
	while(!Des_one.Empty()){
		string tmp = "";
		tmp += Des_one.Top();
		visual.push_back(tmp);
		Des_one.Pop();
	}
	return visual;
}
double result(vector<string> bh){
	Write_stack<double> Des_two;
	double num,op1,op2;
	for(int i = 0;i < bh.size(); i++){
		string tmp = bh[i];
		if(tmp[0] >= '0'&&tmp[0] <= '9'){
			num = atof(tmp.c_str());
			Des_two.Push(num);
		}
		else if(bh[i]=="+")
        {
            op2=Des_two.Top();
            Des_two.Pop();
            op1=Des_two.Top();
            Des_two.Pop();
            Des_two.Push(op1+op2);
        }
        else if(bh[i]=="-")
        {
            op2=Des_two.Top();
            Des_two.Pop();
            op1=Des_two.Top();
            Des_two.Pop();
            Des_two.Push(op1-op2);
        }
        else if(bh[i]=="*")
        {
            op2=Des_two.Top();
            Des_two.Pop();
            op1=Des_two.Top();
            Des_two.Pop();
            Des_two.Push(op1*op2);
        }
        else if(bh[i]=="/")
        {
            op2=Des_two.Top();
            Des_two.Pop();
            op1=Des_two.Top();
            Des_two.Pop();
            Des_two.Push(op1/op2);
        }
	}
	return Des_two.Top();
}
void solve(string str_one){
	str_one = format(str_one);
	vector<string> bh = horizon(str_one);
	double k = result(bh);
	if((int)k == k){
		cout<<k<<endl;
	} else{
		printf("%.1f",k);
		cout<<endl;
	}
	
}
int EvaluateExpressionLess(){
	string str_one;
    getchar();
   // getchar();
	while(getline(cin,str_one)){
		solve(str_one);
	}
}

3. 栈(Stack)与容器(vector) -- 小结

----本文是我在数据结构与算法课程之中的一些笔记心得。我处在学习阶段,有很多方法不甚知晓,只能通过拙劣的模仿来实现目标。我会在下文贴上整个程序的代码块,就当是一种对于现行资料的学习总结吧。

以下是 Stack 部分:

#ifndef _WIRTE_STACK_H_
#define _WIRTE_STACK_H_

#include<iostream>
#include<stdlib.h>
using namespace std;

#define MAXSIZE 10000000
template<class type>
class Write_stack
{
    int top;
    type* my_s;
    int maxsize;

public:
    Write_stack():top(-1),maxsize(MAXSIZE)
    {
        my_s=new type[maxsize];
        if(my_s==NULL)
        {
            cerr<<"分配失败"<<endl;
            exit(1);
        }
    }
    Write_stack(int size):top(-1),maxsize(size)
    {
        my_s=new type[maxsize];
        if(my_s==NULL)
        {
            cerr<<"分配失败"<<endl;
            exit(1);
        }
    }
    ~Write_stack()
    {
        delete[] my_s;
    }
    //检查栈是不是空的
    bool Empty();
    //压入
    void Push(type tp);
    //返回栈顶
    type Top();
    //出栈
    void Pop();
    //栈的大小
    int Size();
};

template<class type>
bool Write_stack<type>::Empty()
{
    if(top==-1){
        return true;
    }
    else
        return false;
}

template<class type>
type Write_stack<type>::Top()
{
    if(top != -1)
    {
        return my_s[top];
    }
    else
    {
        cout<<"这个栈她变空了!!\n";
        exit(1);
    }
}

template<class type>
void Write_stack<type>::Push(type tp)
{
    if(top+1<maxsize)
    {
        my_s[++top]=tp;
    }
    else
    {
        cout<<"栈满\n";
        exit(1);
    }
}

template<class type>
void Write_stack<type>::Pop()
{
    if(top>=0)
    {
        top--;
    }
    else
    {
        cout<<"栈空\n";
        exit(1);
    }
}

template<class type>
int Write_stack<type>::Size()
{
    return top+1;
}

#endif

然后是求解问题的核心代码:

//引入库文件
#include <iostream>
#include "WriteStack.h"
#include<cmath>
#include <string>
#include <algorithm>
#include<stdlib.h>
#include<vector>
//以下为需要定义的常量
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define OVERFLOW -2
#define MAXSIZE 10000000

//设置一些特殊变量
using namespace std;
typedef char SElemType;
typedef int NElemType;
typedef int Status;

//我们开始定义结构体类型
typedef struct {
    SElemType *base;
    SElemType *top;
    int stacksize;
}SqStack_optr; //运算符栈类型

typedef struct {
    NElemType *base;
    NElemType *top;
    int stacksize;
}SqStack_opnd;//操作数栈类型

//我们给一个初始化的函数构造(运算符栈初始化)
Status InitStackS ( SqStack_optr &S )
{
    S.base = new SElemType[MAXSIZE];  
    //新建连续存储空间:类型确定为SElemType, 其大小为 MAXSIZE(10000) 然后赋值给栈底指针 
    if (!S.base)
    return OVERFLOW; 
    //分配失败返回 -2
    S.top = S.base; 
    //把base栈底指针的地址也赋值给栈顶指针
    S.stacksize = MAXSIZE; 
     //赋值栈的容量
    return OK;
}

//我们给一个初始化的函数构造(操作数栈初始化)
Status InitStackN ( SqStack_opnd &S )
{
    S.base = new NElemType[MAXSIZE];  
    //新建连续存储空间:类型确定为SElemType, 其大小为 MAXSIZE(10000) 然后赋值给栈底指针 
    if (!S.base)
    return OVERFLOW; 
    //分配失败返回 -2
    S.top = S.base; 
    //把base栈底指针的地址也赋值给栈顶指针
    S.stacksize = MAXSIZE;  //赋值栈的容量
    return OK;
}

//运算符插入操作
Status PushS( SqStack_optr &S, SElemType e)
{
     if( S.top - S.base == S.stacksize ) //栈满
        return ERROR;
        *S.top ++ = e;
        return OK;
}

//操作数插入操作
Status PushN( SqStack_opnd &S, NElemType e)
{
     if( S.top - S.base == S.stacksize ) //栈满
        return ERROR;
        *S.top ++ = e;
        return OK;
}

//运算符栈出栈操作
Status PopS( SqStack_optr &S, SElemType &e)
{
     if( S.top == S.base ) // 栈变空
       return ERROR;
       e= *--S.top;
       return OK;
}

//操作数栈出栈操作
Status PopN( SqStack_opnd &S, NElemType &e)
{
     if( S.top == S.base ) // 栈变空
       return ERROR;
       e= *--S.top;
       return OK;
}

//运算符栈取栈顶元素
Status GetTopS( SqStack_optr S)
{
    SElemType e;
    if(S.top==S.base)
    return ERROR;
    e=*(S.top-1);
    return e;
}

//操作数栈取栈顶元素
Status GetTopN( SqStack_opnd S)
{
    NElemType e;
    if(S.top==S.base)
    return ERROR;
    e=*(S.top-1);
    return e;
}

//判断 字符c 是否为运算符,如果是运算符,那么返回TRUE。如果不是运算符,那么返回FALSE
Status In(SElemType c)//应在前面有定义 typedef char SElemType
{
    switch(c)
    {   //逐个判断其是否为运算符
        case '+':return TRUE;
        case '-':return TRUE;
        case '*':return TRUE;
        case '/':return TRUE;
        case '%':return TRUE;
        case '(':return TRUE;
        case ')':return TRUE;
        case '#':return TRUE;
        default: return FALSE;
    }
}

//判断运算符的优先级,如果 运算符1 大于 运算符2, OPND出栈,运算符1出栈,完成运算后压栈OPND
//如果 运算符1 小于 运算符2, 运算符2压栈
//如果 运算符1 等于 运算符2,脱括号
SElemType Precede(SElemType t1,SElemType t2)
{  //细心观察其优先级顺序
   SElemType f;
   switch (t2)
   {
   case '+': if(t1=='('||t1=='#')
              f='<';
             else
              f='>';
            break;

   case '-': if(t1=='('||t1=='#')
              f='<';
             else
              f='>';
            break;

    case '*': if(t1=='('||t1=='#'||t1=='+'||t1=='-')
              f='<';
             else
              f='>';
            break;
    case '/': if(t1=='('||t1=='#'||t1=='+'||t1=='-')
              f='<';
             else
              f='>';
            break;
    case '%': if(t1=='('||t1=='#'||t1=='+'||t1=='-')
              f='<';
             else
              f='>';
            break;
  
    case '(': if(t1=='=')
              f='=';
             else
              f='<';
            break;   

    case ')': if(t1=='('||t1=='#')
              f='=';
             else
              f='>';
            break;   

    case '#': if(t1=='('||t1=='#')
              f='=';
             else
              f='>';
            break;          
   }
return f;
}

//
NElemType Operate(NElemType a,SElemType theta,NElemType b)
{
    NElemType c;
    switch(theta)
    {
        case '+':
        c=a+b;
        break;

        case '-':
        c=a-b;
        break;

        case '*':
        c=a*b;
        break;

        case '/':
        c=a/b;
        break;   

        case '%':
        c=a%b;
        break;           
    }
    return c;
}




//主要运算用的程序(个位数)
int EvaluateExpressionOne(){

    SqStack_opnd OPND;
    SqStack_optr OPTR;

    int a,b;
    char ch,x,theta;
    InitStackS(OPTR);
    PushS(OPTR,'#');
    InitStackN(OPND);
    cin>>ch;
    while(ch!='#'||GetTopS(OPTR) != '#')
    {
        if(!In(ch))
        {
          PushN(OPND,ch-'0');
          cin>>ch;
        }             //如果ch不是运算符,则让其进栈
        else
            switch (Precede(GetTopS(OPTR),ch))  //我们来开始比较优先权
            {
                case '<':      //当前字符ch压入OPTR栈,读入下一字符ch
                PushS(OPTR,ch);
                cin>>ch;
                break;

                case '>':      //弹出OPTR栈顶的运算符运算,并将运算结果入栈
                PopS(OPTR,theta);
                PopN(OPND,b);
                PopN(OPND,a);
                PushN(OPND,Operate(a,theta,b));
                break;

                case '=':      //脱括号并开始接受下一个字符的信息
                PopS(OPTR,x);
                cin>>ch;
                break;
            }
           
    } return GetTopN(OPND);
}

//主要运算用的程序(多位数)
int EvaluateExpressionPlural(){

    SqStack_opnd OPND;
    SqStack_optr OPTR;

    int a,b,t,e;
    char ch,x,theta;
    InitStackS(OPTR);
    PushS(OPTR,'#');
    InitStackN(OPND);
    cin>>ch;
    int isnum=0;    //对位数进行判断
    while(ch!='#'||GetTopS(OPTR) != '#')
    {
        if(!In(ch))
        {
            if(isnum==1)
            {
               PopN(OPND,e);
               t=ch-'0';
               PushN(OPND,e*10+t);
               isnum=1;
            cin>>ch;
            }
            else{
          PushN(OPND,ch-'0');
          isnum=1;
          cin>>ch;
          }
        }             //如果ch不是运算符,则让其进栈
        else
        {
            isnum=0;
        
            switch (Precede(GetTopS(OPTR),ch))  //我们来开始比较优先权
            {
                case '<':      //当前字符ch压入OPTR栈,读入下一字符ch
                PushS(OPTR,ch);
                cin>>ch;
                break;

                case '>':      //弹出OPTR栈顶的运算符运算,并将运算结果入栈
                PopS(OPTR,theta);
                PopN(OPND,b);
                PopN(OPND,a);
                PushN(OPND,Operate(a,theta,b));
                break;

                case '=':      //脱括号并开始接受下一个字符的信息
                PopS(OPTR,x);
                cin>>ch;
                break;
            }
        } //else
    } return GetTopN(OPND);
}


//这是为小数计算准备的新方法
Write_stack<char>OPTR_new;
Write_stack<double>OPND_new;

typedef struct 
{//因为在输入表达式时是一个一个的输入字符,而操作数若长度大于2则无法正确得到操作数
 char data[10];
 int length;
}NumberSaving;
bool In_new(char ch)//判断输入的是不是运算符,若是则返回true
{
 if (ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '(' || ch == ')'||ch=='#')
 {
  return true;
 }
 else return false;
}

char Precede_new(char x, char y)//运算符优先级的判断
{
 int Square[2];
 char opnd[2] = { x,y };
 char data_data[7][7] = {
     {'>','>','<','<','<','>','>'},
     {'>','>','<','<','<','>','>'},
     {'>','>','>','>','<','>','>'},
     {'>','>','>','>','<','>','>'},
     {'<','<','<','<','<','=',' '},
     {'>','>','>','>',' ','>','>'},
     {'<','<','<','<','<',' ','='}
 };
 for (int count = 0; count < 2; count++)
 {
  switch (opnd[count])
  {
  case '+':Square[count] = 0;
   break;
  case '-':Square[count] = 1;
   break;
  case '*':Square[count] = 2;
   break;
  case '/':Square[count] = 3;
   break;
  case '(':Square[count] = 4;
   break;
  case ')':Square[count] = 5;
   break;
  case '#':Square[count] = 6;
   break;
  }
     }
 return data_data[Square[0]][Square[1]];
}
double Operate_new(double a, char theta, double b)//加减乘除运算
{
 double result;
 switch (theta)
 {
 case '+': result=a + b;
       break;
 case '-':result= a - b;
       break;
 case '*':result= a * b;
       break;
 case '/':result= a / b;
       break;
  }
 return result ;
}
double CharForNum(NumberSaving NumSave)//将字符数字转换成一个完整的数字型数字
{
 int point=0;//用来判断是否有小数点以及小数点的位置
 double result=0;
 
 for (int i = 0; i < NumSave.length; i++)//先找出小数点的位置
 {
  if (NumSave.data[i] == '.')
   break;
     ++point;
    }
 for (int i=0,j = 0; i < NumSave.length; i++)//根据结构中的length以及小数点位置可以正确转换数字
 {
  if (i != point)//小数点不放入计算
  {
   result += (NumSave.data[i] - '0')*pow(10, point - j - 1);
   j++;
  }
 }
 return result;
}
double EvaluateExpressionPoint()
{
 bool judge = true;//用来判断是否输入了一个数字。如果输入完成了一个数,则让其转化为数字型,存入栈中
 NumberSaving NumSave;//用来记录字符,转换为数字
 OPTR_new.Push('#');//将表达式起始符压入栈中,用于进行判断
 char ch,theta;//记录
 int i=0;
 double a, b;//记录
 cout<<"请输入需要计算的表达式,以'#'结束"<<endl;
 cin >> ch;
 NumSave.length = 0;
 while (ch != '#' || OPTR_new.Top() != '#')// 不能将ch=='#'直接认定为停止循环,因为OPTR中还有加减乘除需要运算
 {
  if (!In_new(ch))
  {
    NumSave.data[i] = ch;
    ++i;
    ++NumSave.length;
    judge = true;
    cin >> ch;
  }
  else {
   if (judge)
   {
    OPND_new.Push(CharForNum(NumSave));//字符转换数字
    NumSave.length = 0; i = 0;//所有回到初始化,用以记录下一个数字
    judge = false;
   }
   switch (Precede_new(OPTR_new.Top(), ch))
   {
       case '>': { 
           theta = OPTR_new.Top();
           OPTR_new.Pop();  //如果栈顶运算符优先级较大,则取OPND栈顶两个数以及OPTR栈顶运算符进行运算,结果再入栈
                   
                   b= OPND_new.Top(); 
                   OPND_new.Pop();
                  
                   a= OPND_new.Top(); 
                   OPND_new.Pop();
                   
                   OPND_new.Push(Operate_new(a, theta, b));
                   break;
               }
       case '<': {
        OPTR_new.Push(ch);
        cin >> ch;
        break;
             }
       case '=': {
        OPTR_new.Pop();
        cin >> ch;
        break;
              }
        }
    }
 }
 return OPND_new.Top();
}




//我们再引入第三种方法
string charactor;
char symbol[6] = { '!','&','|','(',')','#' };
char order[6][6] =
{
	'>', '>', '>', '<', '>', '>',
	'<', '>', '>', '<', '>', '>',
	'<', '<', '>', '<', '>', '>',
	'<', '<', '<', '<', '=', '>',
	'>', '>', '>', '<', '>', '>',
	'<', '<', '<', '<', '>', '=',
};

int findsetting(char option)
{
	for (int i = 0; i < 6; i++)
	{
		if (symbol[i] == option)
			return i;
	}
}

char compare(char a, char b)
{
	int x = findsetting(a);
	int y = findsetting(b);
	return order[x][y];
}

int calculator(int x, int y, char option)
{
	if (option == '|')
		return x | y;
	if (option == '&')
		return x&y;
	return 0;
}

int EvaluateExpressionLogic()
{
    getchar ();
     while (getline(cin, charactor))
	{
		int lens = charactor.size();
		charactor += "#"; 
		charactor += '\0';
		int t, x, y;
		char option;
		int i = 0;
		Write_stack<int>P;
		Write_stack<char>Q;
		Q.Push('#');   //末尾符号“#”
		while (charactor[i] != '#' || Q.Top() != '#')
		{
			if (charactor[i] == '1' || charactor[i] == '0')
		{
		if (charactor[i] == '1')
		t = 1;
		else
		t = 0;
		P.Push(t);
		i++;
		}
			else if (charactor[i] != ' ')
			{
		switch (compare(Q.Top(), charactor[i]))
		{
        case '<': 
		Q.Push(charactor[i]);
		i++;
		break;
		case '=': 
		Q.Pop();
		i++;
		break;
        case '>':  
		if (Q.Top() == '!')
            {  
			x = P.Top();
			P.Pop();
			P.Push(!x);
			Q.Pop();
			}
			else
            {   
			x = P.Top();
			P.Pop();
			y = P.Top();
			P.Pop();
			option = Q.Top();
			Q.Pop(); //计算结果并入栈
			P.Push(calculator(x, y, option));
			}
			break;
				}
			}
		}
		int target = P.Top();
		cout << target;
	}
    return 0;
}

//这是其中的第四种方法

string format(string str_one){
	for(int i = 0;i < str_one.length(); i++){
		if(str_one[i] == '-')
        {
			if(i == 0)
            {
				str_one.insert(0,1,'0');
			}else if(str_one[i-1] == '('){
				str_one.insert(i,1,'0');
			}
		}
		
	}
	return str_one;
}
int orderone(char c){
	if(c == '+' || c == '-'){
		return 1;
	}else if(c == '*' || c == '/'){
		return 2;
	}else{
		return 0;
	}
	
} 
vector<string> horizon(string str_one){
	vector<string> visual;
	Write_stack<char> Des_one;
	for(int i = 0;i < str_one.length(); i++){
		string tmp = "";
		switch(str_one[i]){
			case '+':
			case '-':
			case '*':
			case '/':
				if(Des_one.Empty() || Des_one.Top() == '('){
					Des_one.Push(str_one[i]);
				}else{
					while(!Des_one.Empty() && orderone(Des_one.Top()) >= orderone(str_one[i]) ){
						tmp += Des_one.Top();
						visual.push_back(tmp);
						Des_one.Pop();
						tmp = "";
					}
					Des_one.Push(str_one[i]);
				}
				break;
			case '(':
				Des_one.Push(str_one[i]);
				break;
			case ')':
				while(Des_one.Top() != '('){
					tmp += Des_one.Top();
					visual.push_back(tmp);
					Des_one.Pop();
					tmp = "";
				}
				Des_one.Pop();
				break;
			default:
			if((str_one[i]>='0' && str_one[i]<='9')){
            	tmp += str_one[i];
            	while(i+1<str_one.size() && str_one[i+1]>='0' && str_one[i+1]<='9'||str_one[i+1] == '.')
            	{
                	tmp += str_one[i+1];
                	++i;
   				}
            	visual.push_back(tmp);
  			}
		}
	}
	while(!Des_one.Empty()){
		string tmp = "";
		tmp += Des_one.Top();
		visual.push_back(tmp);
		Des_one.Pop();
	}
	return visual;
}
double result(vector<string> bh){
	Write_stack<double> Des_two;
	double num,op1,op2;
	for(int i = 0;i < bh.size(); i++){
		string tmp = bh[i];
		if(tmp[0] >= '0'&&tmp[0] <= '9'){
			num = atof(tmp.c_str());
			Des_two.Push(num);
		}
		else if(bh[i]=="+")
        {
            op2=Des_two.Top();
            Des_two.Pop();
            op1=Des_two.Top();
            Des_two.Pop();
            Des_two.Push(op1+op2);
        }
        else if(bh[i]=="-")
        {
            op2=Des_two.Top();
            Des_two.Pop();
            op1=Des_two.Top();
            Des_two.Pop();
            Des_two.Push(op1-op2);
        }
        else if(bh[i]=="*")
        {
            op2=Des_two.Top();
            Des_two.Pop();
            op1=Des_two.Top();
            Des_two.Pop();
            Des_two.Push(op1*op2);
        }
        else if(bh[i]=="/")
        {
            op2=Des_two.Top();
            Des_two.Pop();
            op1=Des_two.Top();
            Des_two.Pop();
            Des_two.Push(op1/op2);
        }
	}
	return Des_two.Top();
}
void solve(string str_one){
	str_one = format(str_one);
	vector<string> bh = horizon(str_one);
	double k = result(bh);
	if((int)k == k){
		cout<<k<<endl;
	} else{
		printf("%.1f",k);
		cout<<endl;
	}
	
}
int EvaluateExpressionLess(){
	string str_one;
    getchar();
   // getchar();
	while(getline(cin,str_one)){
		solve(str_one);
	}
}






int main()
{
   cout<<"请输入您想选择的模式:"<<"\n"<<"注意:基础运算模式包括+、-、*、/、%\n“a”为个位数运算(基础版)\n“b”为个位数及以上运算(优化版)"<<endl;
   cout<<"“c”为小数专用运算(升级版)"<<"\n“d”为逻辑运算(强化版)"<<endl;
   cout<<"“e”为负数专用运算(高级版)"<<endl;
   char choose;
   cin>>choose;
   if(choose=='a')
   {
       cout<<"请输入算术表达式,并以#结束。"<<endl;
       cout<<"该运算的表达结果为:"<<EvaluateExpressionOne()<<endl;
   }
   if(choose=='b')
   {
      cout<<"请输入算术表达式,并以#结束。"<<endl;
      cout<<"该运算的表达结果为:"<<EvaluateExpressionPlural()<<endl;
   }
   if(choose=='c')
   {
      
   cout<<"该运算的表达结果为:"<<EvaluateExpressionPoint();
   }

   if(choose=='d')
   {
   
   cout<<"请输入你想计算的逻辑表达式,并以#结束。"<<endl;
   cout<<"该运算的表达结果为:"<<EvaluateExpressionLogic()<<endl;
   
   }//还需要修改
   if(choose=='e')
   {
    cout<<"请输入你想计算的含负数运算表达式,并以#结束。"<<endl;
    cout<<"该运算的表达结果为:"<<EvaluateExpressionLess()<<endl;
	}

   return 0;
}

----以上为本文的所有内容,万望学术长青。