5.前缀、中缀、后缀表达式
5.1 前缀表达式
-
从右至左扫描表达式,遇到数字时,将数字压入堆栈,遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算(栈顶元素 和 次顶元素),并将结果入栈;重复上述过程直到表达式最左端,最后运算得出的值即为表达式的结果
-
中缀表达式转化为前缀表达式的例子:
a+b ---> +,a,b
a+(b-c) ---> +,a,-,b,c
a+(b-c)*d ---> +,a,*,-,b,c,d
a+1+3 ---> +,+,a,1,3
5.2 中缀表达式
1)中缀表达式就是常见的运算表达式.按照人们的顺序来的
代码
package 自己写.栈计算机器;
import java.util.Stack;
public class CalStack {
public static void main(String[] args) {
// String str = "15-6+1*66+88";//5
String str = "15-6+1*66+88";//13
Stackcal numStack = new Stackcal(10);
Stackcal signStack = new Stackcal(10);
int pop1,pop2,rs;
String keepNum = "";
for (int i = 0; i < str.length(); i++) {
int a = 0;
char curSign = str.charAt(i);
if(curSign <=57 && curSign >= 48){
//单位数字
// numStack.push(str.charAt(i) - 48);
keepNum += curSign;
//如果ch已经是expression的最后一位,就直接入栈
if(i == str.length() - 1){
numStack.push(Integer.parseInt(keepNum));
}else {
if(str.charAt(i+1)<=57 && str.charAt(i+1)>=48){
}else {
numStack.push(Integer.parseInt(keepNum));
keepNum = "";
}
}
}else {
if(signStack.ifEmpty()){
signStack.push(curSign);
}else {
int preSign = signStack.pop();
if(signStack.compareBig(preSign) < signStack.compareBig(curSign)){
signStack.push(preSign);
signStack.push(curSign);
}else {
pop1 = numStack.pop();
pop2 = numStack.pop();
rs = numStack.consult(pop1,pop2,preSign);
numStack.push(rs);
signStack.push(curSign);
}
}
}
}
while (signStack.ifEmpty() == false){
pop1 = numStack.pop();
pop2 = numStack.pop();
int sign = signStack.pop();
rs = numStack.consult(pop1,pop2, (char) sign);
System.out.println(rs);
numStack.push(rs);
}
System.out.println(numStack.pop());
}
}
class Stackcal{
private int maxSize;//栈的大小
private int[] stack;//数组,模拟栈,数据放在该数组
private int top = -1;//top表示栈顶,初始化为-1
public Stackcal(int maxSize) {
this.maxSize = maxSize;
stack = new int[this.maxSize];
}
public int getTop(){
return top;
}
/**
* 比较字符串的大小
* @return
*/
public int compareBig(int c){
if(c == '-' || c == '+'){
return 1;
}else if(c == '*' || c== '/'){
return 2;
}else {
return -1;
}
}
//栈满
public boolean ifFull(){
return top == maxSize - 1;
}
//栈空
public boolean ifEmpty(){
return top == -1;
}
//入栈
public void push(int value){
//先判断栈是否满
if(ifFull()){
System.out.println("栈满");
return;
}
top++;
stack[top] = value;
}
//出栈
public int pop(){
if(ifEmpty()){
throw new RuntimeException("栈空");
}
int value = stack[top];
top--;
return value;
}
//显示栈的情况[遍历栈],需要从栈顶开始显示数据
public void list(){
if(ifEmpty()){
System.out.println("栈空,没有数据");
return;
}
for (int i = top; i >= 0; i--) {
System.out.printf("stack[%d] = %d\n" ,i,stack[i]);
}
}
public int consult(int pop1, int pop2, int preSign) {
if(preSign == '+'){
return pop1 + pop2;
}else if(preSign == '-'){
return pop2 - pop1;
}else if(preSign == '/'){
return pop2 / pop1;
}else {
return pop1 * pop2;
}
}
}
5.3 后缀表达式
1)后缀表达式又称逆波兰表达式,与前缀表达式相似,只是运算符位于操作数之后
2)举例说明: (3+4)×5-6 对应的后缀表达式就是 3 4 + 5 × 6 –
后缀表达式的计算机求值
从左至右扫描表达式,遇到数字时,将数字压入堆栈,遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算(次顶元素 和 栈顶元素),并将结果入栈;重复上述过程直到表达式最右端,最后运算得出的值即为表达式的结果
5.3.1 中缀转List字符串
/**
* 中缀转成List字符串
* @param s
* @return
*/
public static List<String> toList(String s){
//定义一个List,存放中缀表达式,对应的内容
List<String> ls = new ArrayList<>();
int i = 0;//指针,用于遍历s;
String str;//对多位数拼接
char c;//遍历到一个字符,就放入到c
do{
if((c = s.charAt(i)) < 48 || (c = s.charAt(i)) >57){
ls.add("" + c);
i++;
}else {
str = "";
while (i < s.length() && (c=s.charAt(i)) > 48 && (c = s.charAt(i)) <=57){
str +=c;
i++;
}
ls.add(str);
}
}while (i < s.length());
return ls;
}
5.3.2 中缀转后缀表达式
-
首先需要初始化两个栈:运算符栈sign1和储存中间结果的栈midn2;
-
从左至右扫描中缀表达式;
-
碰见操作数,将其压midn2;
-
遇到运算符时,比较其与sign1栈顶运算符的优先级:
-
如果sign1为空,或栈顶运算符为左括号“(”,则直接将此运算符入栈;
-
否则,若优先级比栈顶运算符的高,也将运算符压入sign1;
-
否则,将sign1栈顶的运算符弹出并压入到s2中,再次转到(4-1)与sign1中新的栈顶运算符相比较;
-
-
遇到括号时:
(1) 如果是左括号“(”,则直接压入sign1
(2) 如果是右括号“)”,则依次弹出sign1栈顶的运算符,并压入midn2,直到遇到左括号为止,此时将这一对括号丢弃 -
重复步骤2至5,直到表达式的最右边
-
将sign1中剩余的运算符依次弹出并压入midn2
-
依次弹出midn2中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达****式
/**
* 中缀表达式转后缀表达式
* @param ls
* @return
*/
public static List<String> parseList(List<String> ls){
//定义两个栈
Stack<String> signs = new Stack<>();
List<String> s2 = new ArrayList<>();
for (String item :
ls) {
if(item.matches("\\d+")){
s2.add(item);
}else if(item.equals("(")){
signs.push(item);
}else if(item.equals(")")){
while (!signs.peek().equals("(")){
s2.add(signs.pop());
}
signs.pop();
}else {
while (signs.size() != 0 && OperationCompare.getValue(item) <= OperationCompare.getValue(signs.peek())){
s2.add(signs.pop());
}
signs.push(item);
}
}
//
while (signs.size() != 0){
s2.add(signs.pop());
}
return s2;
}
5.3.3 后缀表达式求值过程
例如: (3+4)×5-6 对应的后缀表达式就是 3 4 + 5 × 6 -
/**
* 根据后缀表达式返回得数
* @param ls
* @return
*/
public static int finalRs(List<String> ls){
Stack<String> stack = new Stack<>();
for (String item :
ls) {
if (item.matches("\\d+")){
stack.push(item);
}else {
int num2 = Integer.parseInt(stack.pop());
int num1 = Integer.parseInt(stack.pop());
int result =0;
if(item.equals("+")){
result = num1 + num2;
}else if(item.equals("-")){
result = num1 - num2;
}else if(item.equals("*")){
result = num1 * num2;
}else {
result = num1 / num2;
}
stack.push(result+"");
}
}
return Integer.parseInt(stack.pop());
}