逆波兰计算器

        逆波兰计算器是栈的一种运用方式,一个很简单的式子1+((2+3)*4)-5,心算都能很快算出来,这种式子叫做中缀表达式,我们算起来很方便,但是计算机算起来呢很不方便,有一种计算机很方便计算的方式,叫做后缀表达式,也叫逆波兰表达式。

        逆波兰表达式是波兰逻辑学家J・卢卡西维兹(J・ Lukasewicz)于1929年首先提出的一种表达式的表示方法。后来,人们就把用这种表示法写出的表达式称作“逆波兰表达式”。逆波兰表达式把运算量写在前面,把算符写在后面。

先把1+((2+3)*4)-5的逆波兰表达式写出来:123+4*+5-,这种如何算呢,遇到运算符就将前两个数进行运算然后将结果放回原位置,比如第一个遇到加号,就将2+3=5,将5放回,然后遇到*,5*4=20,将20放回,然后遇到+号,1+20=21,将21放回,然后遇到-,21-5=16,16就是最后的答案,这个过程写起来倒也简单,只要把后缀表达式存入数组,或者倒叙存入栈中,然后一个个读取,只要读取到不是数字,就让前两个数字进行运算就可以了。

代码如下:

        //创建计算后缀表达式的栈        
        ReversePolishLinkedListStack stack = new ReversePolishLinkedListStack();
        while (true) {
            String s = stacks1.pop();//stacks1是存储这后缀表达式逆序的栈
            if (stack.isOper(s)) {//是否是运算符
                int num1 = Integer.parseInt(stack.pop());
                int num2 = Integer.parseInt(stack.pop());
                int cal = stack.cal(num1, num2, s);//加减乘除计算方法
                stack.push(String.valueOf(cal));//入栈
            } else {
                stack.push(s);
            }
            if (stacks1.isEmpty()) {//是否栈空
                break;
            }
        }

后缀表达式的计算我们算好了,接下来就是最重要的一步了,中缀表达式转后缀表达式,具体的步骤呢,我看别人这样写的我就直接粘贴下来了,让我想我也想不出来。过程如下


1) 初始化两个栈:运算符栈s1和储存中间结果的栈 s2; 
2) 从左至右扫描中缀表达式;
3) 遇到操作数时,将其压s2;
4) 遇到运算符时,比较其与s1栈顶运算符的优先级: 

        1.如果s1为空,或栈顶运算符为左括号“(”,则直接将此运算符入栈;
        2.否则,若优先级比栈顶运算符的高,也将运算符压入s1;
        3.否则,将s1栈顶的运算符弹出并压入到 s2 中再次转到(4-1)与s1中新的栈顶运算符相比较;

5) 遇到括号时:(1) 如果是左括号“(”,则直接压入 s1 
                          (2) 如果是右括号“)”,则依次弹出 s1 栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃 。
6) 重复步骤2至5,直到到中缀表达式的最右边。
7) 将s1中剩余的运算符依次弹出并压入 s2 。
8) 依次弹出s2中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式。


代码如下:(代码中标的圆圈123对应的就是上面的步骤)

package datastructure.stack;

import com.sun.deploy.util.StringUtils;

public class ReversePolishExpressionDemo {
    public static void main(String[] args) {
        //中缀转后缀             ①
        ReversePolishLinkedListStack stacks1 = new ReversePolishLinkedListStack();
        ReversePolishLinkedListStack stacks2 = new ReversePolishLinkedListStack();
        //"1", "2", "3", "+", "4", "*", "5", "-", "+"
        String infix = "1+((2+3)*4)-5"; //中缀表达式
        int index = 0; //记录当前扫描到哪个数字了
        String temporary = "";
        int expression_index = 0;
        //将中缀表达式转换为后缀表达式
        while (true) {
            if (Character.isDigit(infix.charAt(index))) {//是数字      ②
                temporary += infix.charAt(index);

                if (index + 1 < infix.length()) {//如果不是最后一个字符
                    index++;
                } else {
                    stacks2.push(temporary);
                    break;//结束循环
                }

                if (!Character.isDigit(infix.charAt(index))) {//下一个不是数字
                    stacks2.push(temporary);//入栈s2
                    temporary = "";//临时字符串置空
                }
            }


            if (!Character.isDigit(infix.charAt(index))) {//不是数字            ③
                if (stacks1.isEmpty()) {
                    stacks1.push(String.valueOf(infix.charAt(index)));
                    index++;
                } else {
                    char currentoper = (char) infix.charAt(index);
                    int current = stacks1.priority(String.valueOf(infix.charAt(index)));//当前扫描的优先级
                    int peek = stacks1.priority(stacks1.peek());//栈顶优先级
                    String peekoper = stacks1.peek();//栈顶符号是什么
                    while (true) {
                        if (stacks1.isEmpty() || '(' == currentoper) {//是左括号  ⑤
                            stacks1.push(String.valueOf(infix.charAt(index)));
                            index++;
                            break;
                        } else if (currentoper == ')') {//如果遇到右括号 ⑤  弹出s1栈顶  压入s2  直到遇到左括号
                            if (!peekoper.equals("(")) {
                                while (true) {
                                    String pop = stacks1.pop();
                                    stacks2.push(pop);
                                    if (stacks1.peek().equals("(")) {
                                        stacks1.pop();
                                        index++;
                                        break;
                                    }
                                }
                                break;
                            }
                        } else if (current > peek) { // ④
                            stacks1.push(String.valueOf(infix.charAt(index)));
                            index++;
                            break;
                        } else {
                            //将s1栈顶弹出,加入s2  然后与新栈顶继续比较
                            String pop = stacks1.pop();
                            stacks2.push(pop);
                        }
                    }
                }
            }

            if (index >= infix.length()) { //⑥
                break;
            }
        }


        while (true) {//将s1的依次弹出加入s2  ⑦
            if (stacks1.isLast()) {
                String pop = stacks1.pop();
                stacks2.push(pop);
                break;
            }
            String pop = stacks1.pop();
            stacks2.push(pop);
        }

        //逆序一下  转换成后缀表达式  ⑧
        while (true) {
            if (stacks2.isLast()) {
                String pop = stacks2.pop();
                stacks1.push(pop);
                break;
            }
            String pop = stacks2.pop();
            stacks1.push(pop);
        }
        stacks1.list();
        System.out.println("===========================");
        ReversePolishLinkedListStack stack = new ReversePolishLinkedListStack();//创建计算后缀表达式的栈
        while (true) {
            String s = stacks1.pop();//stacks1是存储这后缀表达式逆序的栈
            if (stack.isOper(s)) {//是否是运算符
                int num1 = Integer.parseInt(stack.pop());
                int num2 = Integer.parseInt(stack.pop());
                int cal = stack.cal(num1, num2, s);//加减乘除计算方法
                stack.push(String.valueOf(cal));//入栈
            } else {
                stack.push(s);
            }
            if (stacks1.isEmpty()) {//是否栈空
                break;
            }
        }
        System.out.println(infix + "=" + stack.peek());
    }
}


class ReversePolishNode {
    String data;
    ReversePolishNode next;
}

class ReversePolishLinkedListStack {
    ReversePolishNode head = new ReversePolishNode();

    //入栈-push
    public void push(String value) {
        ReversePolishNode xyg = new ReversePolishNode();
        xyg.data = value;
        xyg.next = head.next;
        head.next = xyg;
    }

    //栈空
    public boolean isEmpty() {
        if (head.next == null) {
            return true;
        }
        return false;
    }

    //只剩一个
    public boolean isLast() {
        if (head.next.next == null) {
            return true;
        }
        return false;
    }

    //查看栈首元素
    public String peek() {
        if (isEmpty()) {
            throw new RuntimeException("栈空,没有数据。");
        }
        return head.next.data;
    }

    //出栈-pop
    public String pop() {
        //判断栈是否空
        if (isEmpty()) {
            throw new RuntimeException("栈空,没有数据。");
        }
        String result = head.next.data;
        head.next = head.next.next;
        return result;
    }


    //遍历
    public void list() {
        if (isEmpty()) {
            System.out.println("栈空,没有数据。");
        }
        ReversePolishNode temp = head;
        while (temp.next != null) {
            System.out.print(temp.next.data);
            temp = temp.next;
        }
        System.out.println();
    }


    //返回运算符的优先级,优先级是程序员来确定,优先级使用数字表示
    //数字越大,则优先级就越高。
    public int priority(String oper) {
        if (oper.equals("*") || oper.equals("/")) {
            return 1;
        } else if (oper.equals("+") || oper.equals("-")) {
            return 0;
        } else {
            return -1;//只支持+-*/四种运算符
        }
    }

    //判断是不是一个运算符
    public boolean isOper(String val) {
        return val.equals("+") || val.equals("-") || val.equals("*") || val.equals("/");
    }

    //计算方法
    public int cal(int num1, int num2, String oper) {

        int res = 0;
        switch (oper) {
            case "+":
                res = num1 + num2;
                break;
            case "-":
                res = num2 - num1;
                break;
            case "*":
                res = num1 * num2;
                break;
            case "/":
                res = num2 / num1;
                break;
            default:
                break;
        }
        return res;
    }

}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值