您的位置:首页 > Web前端 > JavaScript

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

2016-04-22 15:46 302 查看
博主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浏览器下结果页面:

还有很对不足之处,欢迎交流。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: