分别用C++和JavaScript 实现四则运算表达式求值

来源:互联网 发布:360网络测速器 5.1.0 编辑:程序博客网 时间:2024/06/17 19:06

博主16年4.19去面腾讯实习生,其中一个问题是让写一个函数求四则运算表达式的值,输入是字符串,输出为表达式结果。当时只记得这是数据结构里堆栈的应用,表达式要变顺序,但是实现就想不起来了,自然程序写的一塌糊涂,结果也就呵呵了。回来之后翻书查资料把程序写出来,供大家参考。程序主要思路参考CSDN中作者wzfxyer 的文档点击打开链接 。

     首先,明确两个个概念“中缀表达式” ”后缀表达式“一般的运算表达式。例如”9+(3-1)*3+10/2“,这是中缀表达式,而”9 3 1- 3 *+10 2 / +“则是后缀表达式,计算后缀表达式的值,先把数字入栈,遇到操作符则栈顶两个数字出栈运算,然后再把结果存入栈中,比如,计算该后缀表达式的过程为 ,①9,3,1入栈,遇到‘-’,计算3-1=2,将2入栈,此时栈中为9,2。②接着3入栈,栈中为9,3,2,然后遇到‘*’,栈顶两个数字3,2出栈计算3*2=6,将6入栈,此时栈中为9,6。③接着遇到‘+’号,栈顶两元素出栈,计算9+6=15,将15入栈,此时栈中为15。④,然后10,2,入栈,最后遇到‘/’,栈顶两数字10,2出栈计算,10/2 =5,并将5入栈,此时栈中为15,5。⑤遇到操作符‘+’,将栈顶两元素弹 出,计算15+5 = 20.入栈再出栈,即为最后结果。

   所以计算表达式的值有两个关键步骤,一是将中缀表达式转为后缀表达式;二是计算后缀表达式的值。中缀表达式转后缀表达式的思想是,从左到右遍历表达式中的每个数字和符号,遇到数字则输出,遇到符号,则要比较其与栈顶元素的优先级,若优先级低于栈顶元素,则将栈顶元素依次输出并将该元素入栈;若优先级高于栈顶元素则入栈;若是遇到左括号,入栈,入栈后的左括号优先级低于+ - * / ;若是遇到右括号,则将栈顶元素依次输出,直到遇到左括号。最后再将栈中元素依次输出,最终输出结果即为后缀表达式。

    程序思想: 定义一个类ExpressionType ,有三个主要函数,一是将字符串中的数字和字符分割出来放到队列中,二是中缀变后缀函数,三是计算后缀表达式的值。其他函数有计算字符串长度,检测左括号和右括号是否匹配(只是为了保证原始字符串没有问题),重载操作符+(是为了把字符串赋给类的变量),两个构造函数。还有一个私有变量,m_string,既要计算的表达式字符串。

     我用VS08新建一个空项目,添加一个ExpressionType.h文件,代码如下:

    #include <string>
    #include <stack>
    #include <queue>
    using namespace std;
    class ExpressionType
    {
    public:
        ExpressionType();
        ExpressionType(string m_string);
       void operator =(string m_string);
       double Calculate();
    private:
        queue<string> DivideExpressionToItem();
        stack<string> ChangeToStuff();
        bool IsWellForm();
        int Size();
    private:
        string m_string;
    };

添加一个ExpressionType.cpp文件,代码如下:

#include <iostream>
#include "ExpressionType.h"
using namespace  std;
ExpressionType::ExpressionType() {
    m_string  = "";
}
    ExpressionType::ExpressionType(string m_string)
{
    this->m_string = m_string;
}
void ExpressionType::operator =(string m_string)
{
    this->m_string = m_string;
}
int ExpressionType::Size()
{
    return m_string.size();
}
bool ExpressionType::IsWellForm()
{
    stack<char> stack;
    int size = Size();
    char ch;
    for ( int i=0;i<size;i++)
    {
        ch = m_string.at(i);
        switch(ch)
        {
        case '(':
            stack.push(ch);break;
        case ')':
            if (stack.empty())
            {
                return false;
            }else
            {
                stack.pop();
            }
            break;
        default:break;
        }
    }
    return stack.empty();
}
queue<string> ExpressionType::DivideExpressionToItem()
{
   queue<string> que;
   if (! IsWellForm())
   {
        cout<<"error"<<endl;
        return que;
   }
   string str ="";
   char ch;
   int size = Size();
   bool isNumber = false;
   for (int i =0;i<size;i++)
   {
       ch = m_string.at(i);
       switch(ch)
       {
       case '0':
       case '1':
       case '2':
       case '3':
       case '4':
       case '5':
       case '6':
       case '7':
       case '8':
       case '9':
       case'.':
           isNumber = true;break;
       case'+':
       case'-':
       case '*':
       case '/':
       case '(':
       case ')':
           isNumber = false;break;
       default:continue;
       }
       if (isNumber)
       {
           str += ch;
           if (i == size -1)
           {
               que.push(str);
           }
       }
       else
       {
           if (str.size() != 0)
           {
               que.push(str);          //如果str之前保存了数据,则先入栈。
           }
               str = ch;                // 如果第一个字符就是操作符号,直接入栈
               que.push(str);
               str = "";
           
       }

   }
   return que;

}
/* 得到优先级,后面优先级高的返回true,否则返回false */
bool ExpressionType::GetProvity(string str1,string str2)
{
    if (str1 == "+" || str1 == "-")
    {
        if (str2 == "(" || str2 == "*" || str2 == "/")     //这些符号的优先级比+,-高。
        {
            return true;
        }
        else
            return false;
    }
    else if (str1 == "*" || str1 == "/")
    {
        if (str2 == "(")
        {
            return true;
        }
        else
            return false;
    }
    if (str1 == "(")                                  //左括号之后的都要入栈,除了右括号,所以此时它的优先级最低
    {
        if (str2 == ")")
        {
            return false;
        }
        else
            return true;
    }
    if (str1 == ")")                        //右括号,一般应该不存在这种情况
    {
        return true;
    }

}
stack<string> ExpressionType::ChangeToStuff()
{
    stack<string> stack_A;
    stack<string> stack_B;
    queue<string> que;
    que = DivideExpressionToItem();
    //cout<< "转换成队列的值"<<que<<endl;
    if (que.empty())
    {
        return stack_B;
    }
    string str;
    /*string str2 ;
    bool probity;*/
    while(!que.empty())
    {
        str = que.front();
        que.pop();
        if (str == "(")
        {
            stack_B.push(str);
        }
        else if (str == ")")
        {
            while(!stack_B.empty()&& stack_B.top() != "(")
            {
                    stack_A.push( stack_B.top());
                    stack_B.pop();
            }
            if (!stack_B.empty())
            {
                stack_B.pop();
            }
        }
        else if (str == "+" || str == "-")
        {
            if (stack_B.empty() || stack_B.top() == "(")
            {
                stack_B.push(str);
            }
            else
            {
                while(!stack_B.empty() && stack_B.top() != "(")
                {
                    stack_A.push(stack_B.top());
                    stack_B.pop();
                }
                stack_B.push(str);

            }
        }
        else if ( str == "*" || str == "/")
        {
             stack_B.push(str);              //简单粗暴,不知道会不会出问题
        }
        else
        {
            stack_A.push(str);                 //数字直接入栈
        }
    }
    //如果b栈中还有操作符,一次弹入a中
    if (!stack_B.empty())
    {
        if (stack_B.top() != "(")
        {
            stack_A.push(stack_B.top());
            stack_B.pop();
        }
    }
    while(!stack_A.empty())
    {
        stack_B.push(stack_A.top());
        cout<< stack_A.top()<<" ";
        stack_A.pop();
    }
    return stack_B;
}
double ExpressionType::Calculate()
{
    stack<string> stack_A = ChangeToStuff();
    if (stack_A.empty())
        return 0;
    stack<double> stack;
    string str;
    char ch;
    double db1;
    while(!stack_A.empty())
    {
        str =stack_A.top();
        stack_A.pop();
        ch = str.at(0);
        switch(ch)
        {
        case '+':
            db1 = stack.top();
            stack.pop();
            db1 += stack.top();
            stack.pop();
            stack.push(db1);
            break;
        case '-':
            db1 = stack.top();
            stack.pop();
            db1 = stack.top() -db1;
            stack.pop();
            stack.push(db1);
            break;
        case '*':
            db1 = stack.top();
            stack.pop();
            db1 *= stack.top();
            stack.pop();
            stack.push(db1);
            break;
        case'/':
            db1 = stack.top();
            stack.pop();
            if (db1 != 0.000)
            {
                db1 = stack.top()/db1;
                stack.pop();
                stack.push(db1);
            }
            break;
        default:
            //将字符串所代表的操作数转换成双精度浮点数并压入栈
            char *p;
            int len = str.length();
            p= (char *)malloc((len+1)*sizeof(char));
            str.copy(p,len,0);
            stack.push(atof(p));
            break;
        }
    }
    return stack.top();
}

主函数ExpressionTypeMain.cpp文件,代码

 #include <iostream>
#include "ExpressionType.h"
int main()
{
    ExpressionType expr;
    expr = "(2.99-4.32)*(90.8-78.66)+78.0/3.14";       //此时的“=”是重载之后的等号。
    //expr = "9+3*2-10/2";
    cout<<"result"<<expr.Calculate()<<endl;
cin.get();
return 0 ;
}

 运行结果为:


JavaScript版: js版刚开始写的,输入即为字符串,没有考虑括号,现在懒得去改了,大家有好的建议,随时交流。主要有四个函数,确定符号优先级函数,中缀转后缀函数,根据操作符和操作数计算结果函数,计算后缀表达式函数。最后将结果输出到页面输入框,并弹出值。代码如下:

/*确定符号优先级函数,若当前元素优先级大于栈顶元素,返回true*/
var priority = function(char1,char2){
    if (char1 == "+" || char1 == "-") {
         if (char2 == "*" || char2 == "/" ){
          return true;
         }else{
          return false;
         }
    }
    if(char1 == "*" || char1 == "/"){
        return false;
    }
}
/*中缀表达式转为后缀表达式,返回存储后缀表达式的数组*/
var fontToBack = function(){
  //var srcData = [9,+,(,3,-,1,),*,3,+,10,.,2];
 // var srcData = srcStr.split("");
var srcData = [9,"+",3,"*",2,"-",10,"/",2];//+,3,*,2,-,2,*,4];
var i,len = srcData.length;
var desData = new Array();
var curData = new Array();
for(i=0;i<len;i++){
  if (typeof(srcData[i]) == "number") {
    desData.push(srcData[i]);
  }else{
          if (curData.length == 0) {
            curData.push(srcData[i]);
          }else{
            for(var j = curData.length -1;j>=0; j--){
              var previous = curData[curData.length -1];
              var key = priority(previous,srcData[i]);
              if (key) {
                curData.push(srcData[i]);
                break;
              }if(!key){
                desData.push(previous);
                curData.pop();
                if (curData.length == 0) {
                  curData.push(srcData[i]);
                }
              }
            }
          }
  }
}
while( curData.length>0){
   desData.push(curData.pop());
}
//alert(desData);
return desData;
}
/*根据操作符和操作数计算结果 */
var count = function(operator,num1,num2){
 // var result;
  if (operator == "+") {
      return (num1 + num2);
  }if (operator == "-") {
    return num1 - num2;
  }if (operator == "*") {
    return num1*num2;
  }if(operator == "/"){}
  return num1 / num2;
}
/*
主函数 ,返回表达式结果
 */
 var countResult = function(arr){
  var reArr = new Array();
  var num1 ,num2,ret;
  arr.forEach(function(item,index,arr){
    if (typeof(item)=="number") {
      reArr.push(item);
    }else{
        num2 = reArr.pop();
        num1 = reArr.pop();
       ret =count(item,num1,num2);
       reArr.push(ret);
    }
  })
 // alert(ret);
  return ret;
 }
// var srcStr = document.getElementById("inData").value;
 var arr = fontToBack();
 //alert(arr);
document.getElementById("outData").value = countResult(arr);

alert(countResult(arr));

我输入的数组是: [9,"+",3,"*",2,"-",10,"/",2];

chrome浏览器下结果页面:


还有很对不足之处,欢迎交流。

1 0
原创粉丝点击