介绍
一般我们见到的算术表达式都是中缀表达式。
如:1 + 2 * (4 - 2) - 3
此时我们的运算思路就是先计算括号中的数,然后计算乘数,最后计算加减。算数运算规则:
1:运算符优先级高的先运算。
2:先括号内,后括号外。
3:同级别先左后右。
但是显然对于计算机来说不太方便计算和判断。因此为把它转换为后缀表达式来计算。
后缀表达式:1242-*+3-
运算符的优先级:
操作符 | 优先级 |
---|---|
+ - | 1 |
* / | 2 |
^ | 3 |
! l o g s c t | 4 |
操作符 | 含义 |
---|---|
! | 阶乘的运算 |
l | 对数ln的运算 |
o | 对数log2的运算 |
g | 开根号的运算 |
s | 三角函数sin的运算 |
c | 三角函数cos的运算 |
t | 三角函数tan的运算 |
思路:
1.遇到数字就加入到后缀表达式链表中。
2.遇到左括号’('就直接入栈。
3.遇到操作符优先级比栈顶操作符优先级低的话,就把栈中优先级大于等于它的依次输出,直到遇到
(1.优先级比它小的
(2.或者是左括号时
(3.或者栈为空时
这三种情况停止出栈,出栈的操作符全部依次加入到后缀表达式链表中。并且把此时的操作符入栈。
4.遇到右括号时,操作符一直出栈,出栈的操作符全部依次加入到后缀表达式链表中。直到遇到左括号是停止,且右括号不入栈。
6.当循环完毕时把栈中的操作符全部出栈,加入后缀表达式链表中。
过程:
步骤 | 中缀表达式 | 堆栈 | 后缀表达式 |
---|---|---|---|
1 | 1+2*(4-2)-3 | ||
2 | +2*(4-2)-3 | 1 | |
3 | 2*(4-2)-3 | + | 1 |
4 | *(4-2)-3 | + | 12 |
5 | (4-2)-3 | +* | 12 |
6 | 4-2)-3 | +*( | 12 |
7 | -2)-3 | +*( | 124 |
8 | 2)-3 | +*(- | 124 |
9 | )-3 | +*(- | 1242 |
10 | )-3 | +*( | 1242- |
11 | )-3 | +* | 1242- |
12 | -3 | +* | 1242- |
13 | -3 | + | 1242-* |
15 | -3 | 1242-*+ | |
16 | 3 | - | 1242-*+ |
17 | - | 1242-*+3 | |
18 | 1242-*+3- |
此时的运算过程为:
遇到数字入栈,遇到操作符出栈运算,并把计算得到的值入栈。
步骤 | 后缀表达式 | 栈堆 | 运算 |
---|---|---|---|
1 | 1242-*+3- | ||
2 | 242-*+3- | 1 | |
3 | 42-*+3- | 12 | |
4 | 2-*+3- | 124 | |
5 | -*+3- | 1242 | |
6 | *+3- | 12 | 4-2=2 |
7 | *+3- | 122 | |
8 | +3- | 1 | 2*2=4 |
9 | +3- | 14 | |
10 | 3- | 1+4=5 | |
11 | 3- | 5 | |
12 | - | 53 | |
13 | 5-3=2 | ||
14 | 2 |
所以最后得到的值为2。我上面定义的其它操作符也可以用。这里就不举例子了。
我用这个方法写过一个带界面的科学计算器。有兴趣的话可以看看。链接如下:
java实现科学计算器
方法实现的代码如下:
private List<String> zhongZhui(String str) {//把输入的字符串转换成中缀表达式。存入list中
int index = 0;
List<String> list = new ArrayList<>();
do{
char ch = str.charAt(index);
if("+-*/^!logsct()".indexOf(str.charAt(index)) >= 0){
//是操作符,直接添加至list中
index ++;
list.add(ch+"");
}else if (str.charAt(index) == 'e' || str.charAt(index) == 'p'){
index ++;
list.add(ch+"");
} else if("0123456789".indexOf(str.charAt(index)) >= 0){
//是数字,判断多位数的情况
String str1 = "";
while (index < str.length() && "0123456789.".indexOf(str.charAt(index)) >= 0){
str1 += str.charAt(index);
index ++;
}
list.add(str1);
}
}while (index < str.length());
return list;
}
public List<String> houZhui(List<String> list){//中缀表达式转换称后缀表达式
Stack<String> fuZhan = new Stack<>();
List<String> list2 = new ArrayList<>();
if (!list.isEmpty()) {
for (int i = 0; i < list.size(); i++) {
if (isNumber(list.get(i))){
list2.add(list.get(i));
} else if (list.get(i).charAt(0) == '('){
fuZhan.push(list.get(i));
} else if (isOperator(list.get(i)) && list.get(i).charAt(0) != '('){
if (fuZhan.isEmpty()){
fuZhan.push(list.get(i));
} else {//符栈不为空
if (list.get(i).charAt(0) != ')'){
if (adv(fuZhan.peek()) <= adv(list.get(i))){
//入栈
fuZhan.push(list.get(i));
} else {//出栈
while (!fuZhan.isEmpty() && !"(".equals(fuZhan.peek())){
if(adv(list.get(i)) <= adv(fuZhan.peek())){
list2.add(fuZhan.pop());
}
}
if (fuZhan.isEmpty() || fuZhan.peek().charAt(0) == '('){
fuZhan.push(list.get(i));
}
}
} else if (list.get(i).charAt(0) == ')'){
while (fuZhan.peek().charAt(0) != '('){
list2.add(fuZhan.pop());
}
fuZhan.pop();
}
}
}
}
while (!fuZhan.isEmpty()){
list2.add(fuZhan.pop());
}
}
// else {
// jTextField1.setText("");
// }
return list2;
}
public static boolean isOperator(String op){//判断是否为操作符
if ("0123456789.ep".indexOf(op.charAt(0)) == -1) {
return true;
} else {
return false;
}
}
public static boolean isNumber(String num){//判断是否为操作数
if ("0123456789ep".indexOf(num.charAt(0)) >= 0) {
return true;
} else {
return false;
}
}
public static int adv(String f){//判断操作符的优先级
int result = 0;
switch(f) {
case "+":
result = 1;
break;
case "-":
result = 1;
break;
case "*":
result = 2;
break;
case "/":
result = 2;
break;
case "^":
result = 3;
break;
case "!":
result = 4;
break;
case "g":
result = 4;
break;
case "l":
result = 4;
break;
case "o":
result = 4;
break;
case "s":
result = 4;
break;
case "c":
result = 4;
break;
case "t":
result = 4;
break;
}
return result;
}
public double math(List<String> list2) {//通过后缀表达式进行计算
Stack<String> stack = new Stack<String>();
for (int i = 0; i < list2.size(); i++) {
if (isNumber(list2.get(i))) {
stack.push(list2.get(i));
} else if (isOperator(list2.get(i))){
double res = 0;
if (list2.get(i).equals("+")) {
double num2 = Double.parseDouble(stack.pop());
double num1 = Double.parseDouble(stack.pop());
res = num1 + num2;
} else if (list2.get(i).equals("-")) {
double num2 = Double.parseDouble(stack.pop());
double num1 = Double.parseDouble(stack.pop());
res = num1 - num2;
} else if (list2.get(i).equals("*")) {
double num2 = Double.parseDouble(stack.pop());
double num1 = Double.parseDouble(stack.pop());
res = num1 * num2;
} else if (list2.get(i).equals("/")) {//除数不能为0
double num2 = Double.parseDouble(stack.pop());
double num1 = Double.parseDouble(stack.pop());
if (num2 != 0){
res = num1 / num2;
} else {
System.out.println("除数不能为0");
//indexYN = 1;
}
} else if (list2.get(i).equals("^")) {
double num2 = Double.parseDouble(stack.pop());
double num1 = Double.parseDouble(stack.pop());
res = Math.pow(num1, num2);
} else if (list2.get(i).equals("!")) {//阶乘必须为自然数
double num1 = Double.parseDouble(stack.pop());
if (num1 == 0 || num1 == 1){
res = 1;
} else if (num1 == (int)num1 && num1 > 1){
int d = 1;
for (int j = (int)num1; j >0; j--) {
d *= j;
}
res = d;
} else {
System.out.println("阶乘必须为自然数");
//indexYN = 1;
}
} else if (list2.get(i).equals("g")) {
double num1 = Double.parseDouble(stack.pop());
res = Math.sqrt(num1);
} else if (list2.get(i).equals("l")) {//ln的x必须大于0
double num1 = Double.parseDouble(stack.pop());
if (num1 > 0){
res = Math.log(num1);
} else {
System.out.println("ln的x必须大于0");
// indexYN = 1;
}
} else if (list2.get(i).equals("o")) {//log的x必须大于0
double num1 = Double.parseDouble(stack.pop());
if (num1 > 0){
res = Math.log(num1) / Math.log(2);
} else {
System.out.println("log的x必须大于0");
//indexYN = 1;
}
} else if (list2.get(i).equals("s")) {
double num1 = Double.parseDouble(stack.pop());
res = Math.sin(num1);
} else if (list2.get(i).equals("c")) {
double num1 = Double.parseDouble(stack.pop());
res = Math.cos(num1);
} else if (list2.get(i).equals("t")) {//tan的x不能为+-(π/2 + kπ)
double num1 = Double.parseDouble(stack.pop());
if (Math.cos(num1) != 0){
res = Math.tan(num1);
} else {
System.out.println("tan的x不能为+-(π/2 + kπ)");
// indexYN = 1;
}
}
stack.push("" + res);
}
}
if (indexYN == 0){
if (!stack.isEmpty()){
return Double.parseDouble(stack.pop());
} else {
return 0;
}
} else {
return -999999;
}
}