|
import java.text.DecimalFormat;
import java.util.Scanner;
import java.util.Stack;
/**
* 简单四则运算,支持的运算符有:加减乘除以及小括号,不支持乘方、开方、中括号等运算符
* 算法实现:
* 栈、二叉树、递归
* 算法思路:
* 以)为界,把相邻两个()中的数字和运算符压栈,然后根据栈构造二叉树,最后递归二叉树求出结果。
* 如计算1+2+3
* +
* /\
* 3 +
* /\
* 1 2
* 计算1+(2*3)/2
*
* +
* /\
* 1 /
* /\
* * 2
* /\
* 2 3
*/
public class Main {
public static void main(String[] args) throws Exception {
Scanner cin = new Scanner(System.in);
int id = 1;
System.out.print("请输入表达式:");
while (cin.hasNext()) {
String str = cin.next();
str = str.replaceAll(" +", "");//删除所有空格
if (!IsExpressionValid(str)) { //检查表达式是否合法
System.out.print("表达式有误,请重新输入:");
continue;
}
Tools tools = new Tools(str); // 辅助类,把输入的表达式传进入
double ans = tools.toValue();
DecimalFormat df = new DecimalFormat("#");
System.out.println(str + "=" + (ans % 1 == 0 ? df.format(ans) : ans));
System.out.print("请输入表达式:");
}
}
public static boolean IsExpressionValid(String str) {
/**
* 开头不能有 + * / )
* 结尾不能有 + - * / (
* 不能出现连续两个运算符
* 不能出现非法字符
* 不能出现 *) 的情况
*/
String regex = "(^[+\\-*-/).].*)|(.*[+\\-*-/(.]$)|(.*[+\\-*/]{2,}.*)|(.*\\(\\)+.*)|(.*[^+\\-*/.()0-9].*)|(.*[+\\-*/]\\).*)";
if (str.matches(regex)) {
return false;
}
Stack<Character> stk = new Stack<>(); //检测括号是否匹配,比如不能出现 (1 + 2)*6)) 的情况
boolean flag = true;
for (int i = 0; i < str.length(); i++) {
if (str.charAt(i) == '(') {
stk.push(str.charAt(i));
} else if (str.charAt(i) == ')') {
if (stk.empty()) {
flag = false;
break;
}
stk.pop();
}
}
return flag && stk.empty();
}
}
class Tools extends Tree { // 辅助类
char[] ch; // 存放输入
String str;//和ch[]存放同一个输入
int i;
public Tools(String str) {
super();
this.str = str;
this.ch = str.toCharArray(); // 把传进来的String转为字符串
this.root = work();
}
public BinaryNode work() { // 对串进行判断,分括号、乘除、加减以及数字或字母 三大部分
Stack<BinaryNode> st = new Stack<BinaryNode>();
while (i < this.ch.length) { // 一切建立在ch[]范围内才执行
double num = 0;
boolean flag = false;
int j = i;
while (i < this.ch.length && ((ch[i] >= '0' && ch[i] <= '9') || ch[i] == '.')) { // 加入数字判断
i++;
flag = true;
}
if (flag) {
String tmp = String.valueOf(ch).substring(j, i);
num = Double.parseDouble(tmp);
st.push(new BinaryNode(String.valueOf(num))); // 如果是数字单独处理
continue;
}
if (ch[i] == '(') { // 左括号,把括号内当成一整个部分入栈
i++;
st.push(work());
} else if (ch[i] == ')') { // 遇到右括号,结束循环自然返回刚进行的栈结果
break;
} else if ((ch[i] == '*' || ch[i] == '/') && ch[i + 1] != '(') {
flag = false;
int k = i + 1;
while (k < this.ch.length && ((ch[k] >= '0' && ch[k] <= '9') || ch[k] == '.')) { // 加入数字判断
k++;
flag = true;
}
BinaryNode bn = null;
if (flag) {
String tmp = String.valueOf(ch).substring(i + 1, k);
num = Double.parseDouble(tmp);
bn = new BinaryNode(String.valueOf(ch[i]), st.pop(),
new BinaryNode(String.valueOf(num)));
i = k - 1;
} else {
bn = new BinaryNode(String.valueOf(ch[i]), st.pop(),
new BinaryNode(String.valueOf(ch[++i])));
}
st.push(bn);
} else {// +或-
st.push(new BinaryNode(String.valueOf(ch[i])));
}
i++;
}
return creattree(st); // 把运算的栈传入creattree返回树结构
}
public BinaryNode creattree(Stack<BinaryNode> stack) { // 对传进来的栈分离,返回树结构
Stack<BinaryNode> t = new Stack<BinaryNode>(); // 倒置栈内元素
BinaryNode bn = null;
int k = 0;
if (stack.size() == 1) {
return stack.peek();
/**-
* 传进来已经是树结构,当只有一个时,直接返回, 如(a+b) 传进来已经是 +
* 这个数结构,直接返回就可以 a b
*/
}
while (!stack.empty()) {
t.push(stack.pop()); // 栈为原来的倒序,转为正序
}
while (!t.isEmpty()) {
if (t.size() < 3) // 输入表达式有错误,如只输入 a+ 这个不完整的表达式
break;
BinaryNode left = t.pop(); // 按顺序循环取出树结构
BinaryNode root = t.pop();
BinaryNode right = t.pop();
bn = new BinaryNode(root.data, left, right);
if (!t.isEmpty()) { // 如果栈里不为空,表示还有节点,将创建的bn节点再放进栈里
t.push(bn);
} else {
break; // 否则退出,此时树结构已经存放在bn
}
}
return bn;
}
public double toValue() {
return this.toValue(this.root);
}
public double toValue(BinaryNode p) {
double num = 0;
if (p == null)
return 0;
if (!p.isLeaf()) {
switch (p.data.charAt(0)) {
case '+':
num = toValue(p.left) + toValue(p.right);
break;
case '-':
num = toValue(p.left) - toValue(p.right);
break;
case '*':
num = toValue(p.left) * toValue(p.right);
break;
case '/':
num = toValue(p.left) / toValue(p.right);
break;
}
return num;
}
return Double.parseDouble(p.data);
}
}
class Tree { // 二叉树类
BinaryNode root;
public Tree(BinaryNode root) {
super();
this.root = root;
}
public Tree() {
super();
this.root = null;
}
}
class BinaryNode // 二叉树的二叉链表结点类
{
public String data; // char类型的数据
public BinaryNode left, right; // 左右分支
public BinaryNode(String data, BinaryNode left, BinaryNode right) { // 放入数据,并放入左右分支
this.data = data;
this.left = left;
this.right = right;
}
public BinaryNode(String data) { // 放入数据,左右分支为空
this(data, null, null);
}
public boolean isLeaf() {
return this.left == null && this.right == null;
}
}
|
|