[編程題] 四則運算
題目描述
請實現如下接口
/* 功能:四則運算
* 輸入: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;
}
}
