오늘의 운동은
1. 키보드를 사용하여 숫자, 대괄호 및 더하기, 빼기, 곱하기 및 나누기의 네 가지 연산 기호를 포함한 수학 공식 문자열을 수신합니다.
2. 문자열을 분석하고 수학 공식을 계산합니다.
인터넷에서 문제 해결 방법과 코드를 설명하는 블로그를 검색했습니다.
https://www.cnblogs.com/menglong1108/p/11619896.html
하지만이 블로그는 소수에 대한 계산이 없어 수정 과정에서 많은 문제가 발생했습니다.
질문을 이해하는 아이디어에 대해 말하며 아마도 정리할 것입니다.
-
먼저 입력 한 수학 연산 식 (예 : 중위 식)을 목록에 저장하여 후 위식으로 쉽게 변환 할 수 있습니다.
-
그런 다음 목록에서 중위 식을 통과하고 후위 표현으로 변환 다음과 같은 아이디어는 다음과 같습니다.
1. 빌드 매장 운영에 스택을, 접미사 표현 저장소 목록 구축
2. 트래버스 첫 번째 목록의 중위 식은 숫자를 만나면 새 목록에 배치됩니다. 연산자를 만나면 별도로 논의해야합니다.a) 연산자 스택이 비어 있거나 스택 맨 위에있는 연산자의 우선 순위가 현재 순회 된 연산자의 우선 순위보다 낮은 경우 (예 : + 및-의 우선 순위가 * 및 /보다 낮음), 스택으로 직접
b) 연산자 스택 비어 있지 않고 스택 맨 위에있는 연산자의 우선 순위가 현재 순회되는 연산자의 우선 순위보다 크거나 같으면 스택 작업이 루프에서 수행되고 현재 연산자보다 우선 순위가 낮은 요소가 나타날 때까지 목록에 추가됩니다. 루프가 실행 된 후 현재 연산자가 스택으로 푸시됩니다.3. 괄호로 이동할 때 : 왼쪽 괄호 인 경우 스택에 직접 밀어 넣고, 오른쪽 괄호가 있으면 왼쪽 괄호를 만날 때까지 스택을 반복합니다. 참고 : 오른쪽 괄호가있는 경우에만 왼쪽 괄호가 스택에서 튀어 나옵니다.
4. 첫 번째 목록을 탐색 한 후 나머지 스택을 차례로 새 목록으로 팝하면 접미사식이됩니다. -
이때 변환 된 접미사식이 새 목록에 저장되고 다음 단계는 접미사 식을 평가하는 것입니다.
1. 새 스택을 만듭니다.
2. 접미사 식을 탐색하고 연산자를 만날 때 번호를 스택으로 직접 푸시합니다. , 그러면 스택 맨 위에있는 두 개의 숫자와 두 번째 스택 맨 위에있는 두 숫자가이 연산자에 의해 연산됩니다. 그리고 결과를 스택에 푸시하고 마지막으로 남은 스택 요소를 답으로 얻습니다.
다음 po는 완전한 코드 (소수점 포함)를 나온 다음 코드에 십진법 연산이 포함 된 위치를 자세히 설명합니다.
package calculation;
/*import java.util.Scanner;
import java.util.List;
import java.util.ArrayList;
import java.util.Stack;*/
import java.util.*;
public class calculation {
private static List<String> parseToSuffixExpression(List<String> expressionList) {
//创建一个栈用于保存操作符
Stack<String> opStack = new Stack<>();
//创建一个list用于保存后缀表达式
List<String> suffixList = new ArrayList<>();
for(String item : expressionList){
//得到数或操作符
if(isOperator(item)){
//是操作符 判断操作符栈是否为空
if(opStack.isEmpty() || "(".equals(opStack.peek()) || priority(item) > priority(opStack.peek())){
//为空或者栈顶元素为左括号或者当前操作符大于栈顶操作符直接压栈
opStack.push(item);
}else {
//否则将栈中元素出栈如队,直到遇到大于当前操作符或者遇到左括号时
while (!opStack.isEmpty() && !"(".equals(opStack.peek())){
if(priority(item) <= priority(opStack.peek())){
suffixList.add(opStack.pop());
}
}
//当前操作符压栈
opStack.push(item);
}
}else if(isNumber(item)){
//是数字则直接入队
suffixList.add(item);
}else if("(".equals(item)){
//是左括号,压栈
opStack.push(item);
}else if(")".equals(item)){
//是右括号 ,将栈中元素弹出入队,直到遇到左括号,左括号出栈,但不入队
while (!opStack.isEmpty()){
if("(".equals(opStack.peek())){
opStack.pop();
break;
}else {
suffixList.add(opStack.pop());
}
}
}else if(".".equals(item)){
//System.out.print('a');
suffixList.add(item);
}else {
throw new RuntimeException("有非法字符!");
}
}
//循环完毕,如果操作符栈中元素不为空,将栈中元素出栈入队
while (!opStack.isEmpty()){
suffixList.add(opStack.pop());
}
return suffixList;
}
/**
* 判断字符串是否为操作符
* @param op
* @return
*/
public static boolean isOperator(String op){
return op.equals("+") || op.equals("-") || op.equals("*") || op.equals("/");
}
/**
* 判断是否为数字
* @param num
* @return
*/
public static boolean isNumber(String num){
return num.matches("^([0-9]{1,}[.][0-9]*)$") || num.matches("^([0-9]{1,})$");
}
/**
* 获取操作符的优先级
* @param op
* @return
*/
public static int priority(String op){
if(op.equals("*") || op.equals("/")){
return 1;
}else if(op.equals("+") || op.equals("-")){
return 0;
}
return -1;
}
/**
* 将表达式转为list
* @param expression
* @return
*/
private static List<String> expressionToList(String expression) {
int index = 0;
List<String> list = new ArrayList<>();
do{
char ch = expression.charAt(index);
if(ch!=46 && (ch <= 47 || ch >= 58)){
//是操作符,直接添加至list中
index ++ ;
list.add(ch+"");
}else{
//是数字,判断多位数的情况
String str = "";
while (index < expression.length() && (expression.charAt(index) >47 && expression.charAt(index) < 58 || expression.charAt(index)==46)){
str += expression.charAt(index);
index ++;
}
list.add(str);
//System.out.println(str);
}
}while (index < expression.length());
return list;
}
/**
* 根据后缀表达式list计算结果
* @param list
* @return
*/
private static double calculate(List<String> list) {
Stack<Double> stack = new Stack<>();
for(int i=0; i<list.size(); i++){
String item = list.get(i);
if(item.matches("^([0-9]{1,}[.][0-9]*)$") || item.matches("^([0-9]{1,})$")){
//是数字
stack.push(Double.parseDouble(item));
}else {
//是操作符,取出栈顶两个元素
double num2 = stack.pop();
//System.out.print(num2);
double num1 = stack.pop();
double res = 0;
if(item.equals("+")){
res = num1 + num2;
}else if(item.equals("-")){
res = num1 - num2;
}else if(item.equals("*")){
res = num1 * num2;
}else if(item.equals("/")){
res = num1 / num2;
}else {
throw new RuntimeException("运算符错误!");
}
stack.push(res);
}
}
return stack.pop();
}
public static boolean isInt(double calculateResult){
double n = calculateResult - (int)calculateResult;
if(n!=0){
return true;
}else{
return false;
}
}
public static void main(String []args){
Scanner sc = new Scanner(System.in);
String expression = sc.nextLine();
List<String> expressionList = expressionToList(expression);
//System.out.println("中缀表达式转为list结构="+expressionList);
//将中缀表达式转换为后缀表达式
List<String> suffixList = parseToSuffixExpression(expressionList);
//System.out.println("对应的后缀表达式列表结构="+suffixList);
//根据后缀表达式计算结果
double calculateResult = calculate(suffixList);
if(isInt(calculateResult)){
System.out.printf(expression+"=%.2f\n",calculateResult);
}else{
System.out.printf(expression+"="+ (int)calculateResult);
}
sc.close();
}
}
이 코드는 이전 po 페이지의 코드를 최적화합니다.
- 소수 계산 가능
- 휴대폰의 컴퓨터와 마찬가지로 최종 계산 결과가 정수이면 출력 답변에는 소수점이 포함되지 않고 계산 결과는 소수점, 출력 답변은 10 진수입니다.
구체적인 변경 사항은 다음과 같습니다.
- 75 행은 첫 번째 목록의 값이 숫자인지 판단 할 때 소수와 일치 할 수있는 정규식을 추가합니다.
- 102 행과 109 행 (첫 번째 목록 작성)은 소수점 판정을 추가했으며 소수점이면 str에도 추가됩니다.
- 129 행은 소수 계산을 추가합니다.
- 155-162 행은 결과가 정수인지 소수인지를 추가합니다.
결과는 다음과 같습니다.