[编程题] 四则运算
作者:互联网
[编程题] 四则运算
题目描述
请实现如下接口
/* 功能:四则运算
* 输入:strExpression:字符串格式的算术表达式,如: "3+2*{1+2*[-4/(8-6)+7]}"
* 返回:算术表达式的计算结果
*/
public static int calculate(String strExpression)
{
/* 请实现*/
return 0;
}
约束:
- pucExpression字符串中的有效字符包括[‘0’-‘9’],‘+’,‘-’, ‘*’,‘/’ ,‘(’, ‘)’,‘[’, ‘]’,‘{’ ,‘}’。
- pucExpression算术表达式的有效性由调用者保证;
输入描述:
输入一个算术表达式
输出描述:
得到计算结果
输入例子1:
3+2*{1+2*[-4/(8-6)+7]}
输出例子1:
25
个人方法(python)
# !/usr/bin/env python2
# -*- coding:utf-8 -*-
opts = '+-*/()[]{}'
Wopt = {'(':0,'[':1,'{':2,'+':3,'-':3, '*':4, '/':4}
# 字符串 转 中缀表达式(infix) : str->list
# 目的为了 分离 多位的整数、负数以及运算符
def str2infix(line):
infix = []
numtmp = ''
for ch in line:
if ch not in opts:
numtmp += ch
else:
if ch == '-': # 分离负数
if len(infix) != 0:
if infix[-1] in "([{" and numtmp=='':
numtmp += ch
continue
if numtmp != '':
infix.append(numtmp)
numtmp = ''
infix.append(ch)
if numtmp != '':
infix.append(numtmp)
return infix
# 中缀表达式(infix) 转 后缀表达式(posfix)
def infix2posfix(infix):
posfix = []
oprtmp = []
for v in infix:
if v not in opts:
posfix.append(v)
else:
if len(oprtmp) == 0:
oprtmp.append(v)
elif v in '([{':
oprtmp.append(v)
elif v in ')]}':
while True:
ele = oprtmp.pop()
if ele in '([{':
break
# posfix.append(ele)
# if Wopt[ele] < Wopt[oprtmp[-1]]:
posfix.append(ele)
# break
elif Wopt[v] <= Wopt[oprtmp[-1]]:
while Wopt[v] <= Wopt[oprtmp[-1]]:
posfix.append(oprtmp.pop())
if len(oprtmp) == 0:
break
oprtmp.append(v)
else:
oprtmp.append(v)
while len(oprtmp) != 0:
posfix.append(oprtmp.pop())
return posfix
# 后缀表达式求值
def calculate(posfix):
expr = []
for ele in posfix:
if ele in '-+/*':
n1, n2 = expr.pop(), expr.pop()
if ele == '+':
expr.append(n2 + n1)
elif ele == '-':
expr.append(n2 - n1)
elif ele == '*':
expr.append(n2 * n1)
else:
expr.append(n2 / n1)
else:
expr.append(int(ele))
return expr
# 字符串中的有效字符包括[‘0’-‘9’],‘+’,‘-’, ‘*’,‘/’ ,‘(’, ‘)’,‘[’, ‘]’,‘{’ ,‘}’。
try:
while True:
line = raw_input()
# line = '3+2*{1+2*[-4/(8-6)+7]}'
# line = '3*5+8-0*3-6+0+0'
# line = '5-3+9*6*(6-10-2)'
# line = '3-10+(0+(10+5+3)-10)'
if line=='':
break
infix = str2infix(line)
posfix = infix2posfix(infix)
# print infix
# print posfix
print calculate(posfix)[0]
# break
except:
pass
优秀解析
1. Python一行代码(py2,py3)
# python2
print(int(eval(raw_input().replace("{","(").replace("}",")").replace("[","(").replace("]",")"))))
# python3
print(int(eval(input().replace("{","(").replace("}",")").replace("[","(").replace("]",")"))))
说明:
eval字符串参数合法的字符包括”+, -, *, /, (, )”,”0-9”(没有“[]”,”{}“)
所以下面的仅仅是处理带小括号的 表达式求值。同时上面也仅仅是把大、中括号替换为小括号。
# python2
print(eval(raw_input()))
# python3
print(eval(input()))
2. 传统方法,计算中缀表达式(java)
传统方法,直接通过两个栈,计算中缀表达式的值
import java.util.*;
public class Main{
// 用于存放一个正括号的集合, 用于简化代码
static Set<Character> brace = new HashSet<>();
public static void main(String ... args){
Scanner sc = new Scanner(System.in);
// 初始化正括号集合
brace.add('{');
brace.add('(');
brace.add('[');
while(sc.hasNextLine()){
// 对字符串做初始化处理,原则有二:
// 1、处理负数,这里在-前面的位置加入一个0,如-4变为0-4,
// 细节:注意-开头的地方前面一定不能是数字或者反括号,如9-0,(3-4)-5,这里地方是不能加0的
// 它的后面可以是数字或者正括号,如-9=>0-9, -(3*3)=>0-(3*3)
// 2、处理字符串,在最后的位置加#, 主要是为了防止最后一个整数无法处理的问题
String exp = sc.nextLine().replaceAll("(?<![0-9)}\\]])(?=-[0-9({\\[])", "0") + "#";
System.out.println(calculate(exp));
}
}
private static int calculate(String exp){
// 初始化栈
Stack<Integer> opStack = new Stack<>();
Stack<Character> otStack = new Stack<>();
// 整数记录器
String num = "";
for(int i = 0; i < exp.length(); i++){
// 抽取字符
char c = exp.charAt(i);
// 如果字符是数字,则加这个数字累加到num后面
if(Character.isDigit(c)){
num += c;
}
// 如果不是数字
else{
// 如果有字符串被记录,则操作数入栈,并清空
if(!num.isEmpty()){
int n = Integer.parseInt(num);
num = "";
opStack.push(n);
}
// 如果遇上了终结符则退出
if(c == '#')
break;
// 如果遇上了+-
else if(c == '+' || c == '-'){
// 空栈或者操作符栈顶遇到正括号,则入栈
if(otStack.isEmpty() || brace.contains(otStack.peek())){
otStack.push(c);
} else {
// 否则一直做弹栈计算,直到空或者遇到正括号为止,最后入栈
while(!otStack.isEmpty() && !brace.contains(otStack.peek()))
popAndCal(opStack, otStack);
otStack.push(c);
}
}
// 如果遇上*/
else if(c == '*' || c == '/'){
// 空栈或者遇到操作符栈顶是括号,或者遇到优先级低的运算符,则入栈
if(otStack.isEmpty()
|| brace.contains(otStack.peek())
|| otStack.peek() == '+' || otStack.peek() == '-'){
otStack.push(c);
}else{
// 否则遇到*或/则一直做弹栈计算,直到栈顶是优先级比自己低的符号,最后入栈
while(!otStack.isEmpty()
&& otStack.peek() != '+' && otStack.peek() != '-'
&& !brace.contains(otStack.peek()))
popAndCal(opStack, otStack);
otStack.push(c);
}
} else {
// 如果是正括号就压栈
if(brace.contains(c))
otStack.push(c);
else{
// 反括号就一直做弹栈计算,直到遇到正括号为止
char r = getBrace(c);
while(otStack.peek() != r){
popAndCal(opStack, otStack);
}
// 最后弹出正括号
otStack.pop();
}
}
}
}
// 将剩下的计算完,直到运算符栈为空
while(!otStack.isEmpty())
popAndCal(opStack, otStack);
// 返回结果
return opStack.pop();
}
private static void popAndCal(Stack<Integer> opStack, Stack<Character> otStack){
int op2 = opStack.pop();
int op1 = opStack.pop();
char ot = otStack.pop();
int res = 0;
switch(ot){
case '+':
res = op1 + op2;
break;
case '-':
res = op1 - op2;
break;
case '*':
res = op1 * op2;
break;
case '/':
res = op1 / op2;
break;
}
opStack.push(res);
}
private static char getBrace(char brace){
switch(brace){
case ')':
return '(';
case ']':
return '[';
case '}':
return '{';
}
return '#';
}
}
3. 中缀字符串转变为后缀字符串数组并求解(c++)
//思路:
//1.字符串预处理,针对可能出现的“{,},[,],-”等特殊情况进行替换,判断‘-’是负号还是减号,负号前面+0,转变成减法运算
//2.将中缀字符串转变为后缀字符串数组
//3.对后缀字符串数组进行求解
#include<iostream>
#include<vector>
#include<string>
#include<stack>
#include<sstream>
using namespace std;
bool cmpPriority(char top,char cur)//比较当前字符与栈顶字符的优先级,若栈顶高,返回true
{
if((top=='+' || top=='-') && (cur=='+' || cur=='-'))
return true;
if((top=='*' || top=='/') && (cur=='+' || cur=='-'|| top=='*' || top=='/'))
return true;
if(cur==')')
return true;
return false;
}
void preProcess(string &str)//对字符串进行预处理
{
for(int i=0;i<str.size();++i)
{
if(str[i]=='{')//将‘{、}、[,]’替换成'()'
str[i]='(';
else if(str[i]=='}')
str[i]=')';
else if(str[i]=='[')
str[i]='(';
else if(str[i]==']')
str[i]=')';
else if(str[i]=='-')
{
if(i==0)//将'-'前面添加0转变成减法运算
str.insert(0,1,'0');
else if(str[i-1]=='(')
str.insert(i,1,'0');
}
}
}
vector<string> mid2post(string &str)
{
vector<string>vstr;
stack<char>cstack;
for(int i=0;i<str.size();++i)//扫描字符串
{
string temp="";
if(str[i]>='0' && str[i]<='9')//若是数字
{
temp+=str[i];
while(i+1<str.size() && str[i+1]>='0' && str[i+1]<='9')
{
temp+=str[i+1];//若是连续数字
++i;
}
vstr.push_back(temp);
}
else if(cstack.empty() || str[i]=='(')//若栈空或者字符为'('
cstack.push(str[i]);
else if(cmpPriority(cstack.top(),str[i]))//若栈顶元素优先级较高,栈顶元素出栈
{
if(str[i]==')')//若当前字符是右括号,栈中元素出栈,入字符串数组中,直到遇到'('
{
while(!cstack.empty() && cstack.top()!='(')
{
temp+=cstack.top();
cstack.pop();
vstr.push_back(temp);
temp="";
}
cstack.pop();
}
else//栈中优先级高的元素出栈,入字符串数组,直到优先级低于当前字符
{
while(!cstack.empty() && cmpPriority(cstack.top(),str[i]))
{
temp+=cstack.top();
cstack.pop();
vstr.push_back(temp);
temp="";
}
cstack.push(str[i]);
}
}
else//当前字符优先级高于栈顶元素,直接入栈
cstack.push(str[i]);
}
while(!cstack.empty())//栈中还存在运算符时,出栈,存入字符串数组
{
string temp="";
temp+=cstack.top();
cstack.pop();
vstr.push_back(temp);
}
return vstr;
}
int calcPostExp(vector<string> & vstr)//对后缀表达式进行求值,主要是根据运算符取出两个操作数进行运算
{
int num,op1,op2;
stack<int>opstack;
for(int i=0;i<vstr.size();++i)
{
string temp=vstr[i];
if(temp[0]>='0' && temp[0]<='9')//如果当前字符串是数字,利用字符串流转化为int型
{
stringstream ss;
ss<<temp;
ss>>num;
opstack.push(num);
}
else if(vstr[i]=="+")//若是操作符,取出两个操作数,进行运算,并将结果存入
{
op2=opstack.top();
opstack.pop();
op1=opstack.top();
opstack.pop();
opstack.push(op1+op2);
}
else if(vstr[i]=="-")
{
op2=opstack.top();
opstack.pop();
op1=opstack.top();
opstack.pop();
opstack.push(op1-op2);
}
else if(vstr[i]=="*")
{
op2=opstack.top();
opstack.pop();
op1=opstack.top();
opstack.pop();
opstack.push(op1*op2);
}
else if(vstr[i]=="/")
{
op2=opstack.top();
opstack.pop();
op1=opstack.top();
opstack.pop();
opstack.push(op1/op2);
}
}
return opstack.top();//最终的栈顶元素就是求解的结果
}
void calcExp(string str)
{
vector<string>vstr;
preProcess(str);//对字符串进行预处理
vstr=mid2post(str);//将中缀表达式转为后缀,保存在字符串数组中,方便下一步求解
int res=calcPostExp(vstr);
cout<<res<<endl;
}
int main()
{
string str;
while(getline(cin,str))
{
calcExp(str);
}
return 0;
}
3. 统一小括号,中缀表达式转后缀并求解(c++)
思路是很正常的思路
-
先把中括号和大括号换成小括号,方便后续处理
-
四则运算:中缀表达式转后缀表达式,中途计算算出后缀表达式结果
#include<iostream>
#include<string>
#include<stack>//栈头文件
using namespace std;
string change_bracket(string exp);//将大括号和中括号转成小括号,同时,将负数x转成0-x的形式
int mid_to_post(string exp);
int calculate(int a, int b, char sym);
int main()
{
string exp;
while (cin >> exp)
{
exp = change_bracket(exp);
int exp_post = mid_to_post(exp);
cout << exp_post << endl;
}
return 0;
}
//把大括号和中括号换成小括号,以便减少后期过多的判断
string change_bracket(string exp)
{
for (int i = 0; i < exp.size(); i++)
{
if (exp[i] == '{' || exp[i] == '[')
exp[i] = '(';
if (exp[i] == '}' || exp[i] == ']')
exp[i] = ')';
}
//cout << exp;
return exp;
}
int mid_to_post(string exp)
{
int flag = 0;//正负号标志,0为无正负号,1为正号,2为负号
stack<int> exp_post;//数字栈
stack<char> symbol;//符号栈
for (int i = 0; i < exp.size(); i++)
{
char temp;
if (isdigit(exp[i]))//为数字时
{
int j = i,num=0;
while (i + 1 < exp.length() && isdigit(exp[i + 1])) i++;
string str_num = exp.substr(j, i - j+1);
for (int k = 0; k < str_num.size(); k++)
num = num * 10 + str_num[k] - '0';
if (flag == 2)
num = 0 - num;
flag = 0;
exp_post.push(num);
}
else if (exp[i] == '*' || exp[i] == '/' || exp[i] == '(')//为乘除时
symbol.push(exp[i]);
else if (exp[i] == '+'||exp[i] == '-')//为加减时
{
/*处理负号先*/
if (!i || exp[i - 1]=='(')
if (exp[i] == '+')
flag = 1;
else
flag = 2;
/*处理负号先_end*/
while (!flag&&!symbol.empty() && symbol.top() != '(')//堆栈非空时,符号栈弹出符号,并结合数字栈计算
{
int b = 0, a = 0;
char sym_temp;
b = exp_post.top();
exp_post.pop();
a = exp_post.top();
exp_post.pop();
sym_temp = symbol.top();
symbol.pop();
exp_post.push(calculate(a, b, sym_temp));//计算结果入栈
}
if(!flag) symbol.push(exp[i]);
}
else if (exp[i] == ')')//为右括号时
{
while (symbol.top() != '(')
{
int b = 0, a = 0;
char sym_temp;
b = exp_post.top();
exp_post.pop();
a = exp_post.top();
exp_post.pop();
sym_temp = symbol.top();
symbol.pop();
exp_post.push(calculate(a, b, sym_temp));//计算结果入栈
}
symbol.pop();
}
else
cout << "Input error!!!" << endl;
}
//循环结束后把剩下的符号弹出,并结合数字栈计算
while (!symbol.empty())
{
int b = 0, a = 0;
char sym_temp;
b = exp_post.top();
exp_post.pop();
a = exp_post.top();
exp_post.pop();
sym_temp = symbol.top();
symbol.pop();
exp_post.push(calculate(a, b, sym_temp));//计算结果入栈
}
return exp_post.top();
}
int calculate(int a,int b,char sym)
{
switch (sym)
{
case '+': return a + b;
case '-': return a - b;
case '*': return a * b;
case '/': return a / b;
default:
return 0;
break;
}
}
参考
-
简单算术表达式求值 https://blog.csdn.net/dnxbjyj/article/details/71248637
-
首页 > 试题广场 > 四则运算 https://www.nowcoder.com/questionTerminal/9999764a61484d819056f807d2a91f1e
标签:编程,opstack,int,top,四则运算,pop,exp,otStack 来源: https://www.cnblogs.com/oucbl/p/12556192.html