[编程题] 四则运算

[编程题] 四则运算

题目描述

请实现如下接口

/* 功能:四则运算
* 输入:strExpression:字符串格式的算术表达式,如: "3+2*{1+2*[-4/(8-6)+7]}"
* 返回:算术表达式的计算结果
*/

public static int calculate(String strExpression)
{
    /* 请实现*/
    return 0;
}

约束:

  1. pucExpression字符串中的有效字符包括[‘0’-‘9’],‘+’,‘-’, ‘*’,‘/’ ,‘(’, ‘)’,‘[’, ‘]’,‘{’ ,‘}’。
  2. 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++)

思路是很正常的思路

  1. 先把中括号和大括号换成小括号,方便后续处理
  2. 四则运算:中缀表达式转后缀表达式,中途计算算出后缀表达式结果
#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;
    }
}

参考

  1. 简单算术表达式求值 https://blog.csdn.net/dnxbjyj/article/details/71248637
  2. 首页 > 试题广场 > 四则运算 https://www.nowcoder.com/questionTerminal/9999764a61484d819056f807d2a91f1e

原文地址:https://www.cnblogs.com/oucbl/p/12556192.html

时间: 2024-10-02 16:13:22

[编程题] 四则运算的相关文章

20165223 结对编程之四则运算

目录 一.结对对象 二.需求分析 三.设计思路 四.UML类图 五.功能截图 六.结对感受 一.结对对象 担任角色 驾驶员(Driver):20165223 蔡霓(是控制键盘输入的人) 领航员(Navigator):20165218 赵冰雨(起到领航.提醒的作用) 搭档本次结对博客: 本次结对码云链接: 二.需求分析 取自<结对编程项目-四则运算> 题目内容(week1) 实现一个命令行程序,要求: 自动生成小学四则运算题目(加.减.乘.除) 支持整数 支持多运算符(比如生成包含100个运算符

20165206 结对编程项目-四则运算 阶段一总结

20165206 结对编程项目-四则运算 阶段一总结 一.需求分析 通过命令行输入生成题目的数量,随机生成题目. 生成的题目不重复. 生成的四则运算题目支持整数.支持多运算符. 能够根据作答情况统计正确的个数. 二.设计思路 设计一个类来实现整数的四则运算. 用一个循环结构来生成随机数,生成题目. 设计一个类来比较输入的答案与正确答案是否一致. 判断做的题是否正确,并返回正确的个数. 设计单元测试,对代码进行测试及修改 UML图: 三.核心代码 生成随机数: while(true){ a=new

20165318 结对编程项目-四则运算 阶段总结

20165318 结对编程项目-四则运算 阶段总结 一.需求分析 能随机生成n道四则运算题目,n由使用者输入 支持整数和分数 支持多运算符 能够判断正误,错误时能提醒并输出正确答案 能计算出正确率 能多次生成题目,直到使用者选择退出 后续拓展的可能 题目去重 文件: 处理生成题目并输出到文件 完成题目后从文件读入并判题 多语言支持:简体中文, 繁體中文, English 二.设计思路(同时输出UML类图) 首先考虑生成题目. 随机生成题目,用到Random函数,生成题目应该是同时随机生成数字和四

20165214 结队编程项目-四则运算(第二周)

20165214 第一次结队编程项目--四则运算第二周 需求分析 本周的结队编程想要实现一个四则运算系统,它可以自动生成n个计算题(本周不包括分数),其中n由我们输入.每输出一道题目,运行程序的人需要输入相应的答案,直到最后一道题做完.最后,统计正确率.然后,在这个基础上可以进行相应的功能扩展,比如语言支. 设计思路 我需要在上周的基础上对程序进行补充.在题目的生成上,应该再加上括号.÷./ 本周达成: ①能够随机生成n道题目,n由我们输入,最大长度可直接在程序里面修改: ②支持真分数运算: ③

20165230 结对编程项目-四则运算 整体总结

20165230 结对编程项目-四则运算 整体总结 一.需求分析 随机生成题目 生成的题目个数从命令行输入 用户可选择生成不同难度的题目,比如通过参数指定: (1) 运算符个数范围 (2) 运算符限定(小学一年级题目只生成 + - 题目) 能多次生成题目 题目运算(判题) 支持多运算符 支持整数 支持真分数 题目合法性判断 可独立使用 可用于测试生成题目的正确性 扩展需求 题目去重 支持多语言 处理生成题目并输出到文件 完成题目后从文件读入并判题 二.设计思路 设计一个IntNumber类,用来

20165330 结对编程项目-四则运算 第二周

需求分析 实现一个命令行程序,要求:自动生成小学四则运算题目(加.减.乘.除) 可实现多个运算符一起运算 可以真分数形式输出结果 测试结果的正确性 统计题目完成数并计算正确率 设计思路 实验首先是完成一个计算器的功能,可以实现简单的+.-.*./运算,在这里设计一个主类生成随机数,生成题目,并判断正确率 实现多运算符,编入四个类分别实现整数运算.真分数运算.判断结果正确并计算正确率 利用JUnit检测非法输入 设计测试类,利用JUnit测试整数类与分数类的四则运算 UML类图 功能截图 Juni

20175212童皓桢 结对编程项目-四则运算 第一周

20175212童皓桢 结对编程项目-四则运算 第一周 需求分析 实现一个命令行程序,要求自动生成小学四则运算题目(加减乘除) 支持多运算符 测试结果的正确性,用户输入错误时给出正解 统计题目正确率 设计思路 首先要能够按照按人的一般习惯,生成自左向右计算的加减乘除算式. 随机生成多运算符,并随机生成相对应个数的整数 利用eval方法直接计算随机生成的算式的值,并和用户的输入作比较 判断正确率 设计测试类,利用JUnit测试整数的四则运算 UML类图 关键代码 如何生成符合要求格式的运算式 fo

20175209王梓鸿 结对编程项目—四则运算 第一周 阶段总结

20175209王梓鸿 结对编程项目-四则运算 第一周 阶段总结 一.需求分析 1.题目要求: 实现一个命令行程序,要求: 自动生成小学四则运算题目(加.减.乘.除) 支持整数 支持多运算符(比如生成包含100个运算符的题目) 支持真分数 统计正确率 扩展需求 文件 处理生成题目并输出到文件 完成题目后从文件读入并判题 多语言支持简体中文,繁體中文,English 生成题目去重 二.设计思路 1.编写背景及完成情况 在开始写设计思路之前,我觉得应该说一下我们编写的情况(可能有些跑题).这次结对的

20175325 第一周结对编程项目 四则运算

20175325 第一周结对编程项目 四则运算 一.需求分析: 能根据用户输入的数字生成四则运算的题目数量 能自动生成规定范围内的四则运算题目(加.减.乘.除) 能够判断四则运算的结果是否正确并进行数量统计 能多次生成四则运算题目 支持多运算符 用户能够选择是否开始答题 统计题目正确率 题目去重 多语言支持:简体中文, 繁體中文, English 文件: 处理生成题目并输出到文件 完成题目后从文件读入并判题 二.设计思路: 和之前所学的C语言中的四则运算方法作类比,在JAVA中运用了C语言里的一