栈应用-中缀表达式转后缀表达式并计算值

表达式的三种形式:
中缀表达式:运算符放在两个运算对象中间,如:(2+1)*3。我们从小做数学题时,一直使用的就是中缀表达式。
后缀表达式:不包含括号,运算符放在两个运算对象的后面,所有的计算按运算符出现的顺序,严格从左向右进行(不再考虑运算符的优先规则),如:2 1 + 3 。又比如3+(6-4/2)5=23的后缀表达式为:3642/-5+# (#符号为结束符)
前缀表达式:同后缀表达式一样,不包含括号,运算符放在两个运算对象的前面,如:
+ 2 1 3 。前缀表达式和后缀表达式其实是差不多的,只不过符号位置不同而已,前缀表达式不是很常见。

中缀转后缀表达式

有两个栈:运算符栈和操作数栈
简述:左括号直接压入,压入右括号,则要一直弹出到左括号(左括号舍弃)。
压入低运算符到【运算符栈】的时候, 先将高于/等于该运算符级别的【运算符栈】栈顶运算符弹出。

  1. 从左到右扫描
  2. 若读到是操作数,则判断操作数的类型,并将操作数存入【操作数栈】
  3. 若读到的是运算符
    3.1 若为左括号“(”,则直接存入【运算符栈】
    3.2 若为右括号“)”,则弹出【运算符栈】的运算符,直到遇到左括号为止,此时抛弃该左括号。
    3.3 运算符为非括号运算符
    a. 若【运算符栈】栈顶的运算符为左括号,则直接存入【运算符栈】
    b. 若比【运算符栈】栈顶的运算符优先级高,则直接存入【运算符栈】。
    c. 若比【运算符栈】栈顶的运算符优先级低或相等,则输出栈顶运算符到【操作数栈】,直到【运算符栈】栈顶运算符低于(不包括等于)该运算符优先级或为左括号,并将当前运算符压入【运算符栈】
    ps:从【运算符】栈顶依次弹出所有【高于或等于】当前运算符的运算符,遇到左括号或低于该当前运算符的则停止,并将当前运算符压入【运算符栈】。
  4. 当读取完成后运算符栈中尚有运算符时,则依序取出运算符到【操作数栈】直到【运算符栈】为空。

代码

	package com.gkwind.structure.stack;
	
	import java.util.NoSuchElementException;
	
	/**
	 * 四则运算
	 * 队列实现操作数栈,栈实现运算符栈
	 *
	 * @Author thewindkee
	 * @Date 2019/7/9 0009 下午 2:16
	 */
	public class MathOperation2 {
	
	    public MathOperation2() {
	    }
	
	    public Integer calculate(String expr) {
	        LinkedQueue<String> numStack = mapToNumStack(expr);
	        System.out.println("numStack"+numStack);
	        int result = exec(numStack);
	        return result;
	    }
	
	    /**
	     * 遍历后缀表达式
	     * 将数字压栈,遇到操作符则弹出栈顶的两个元素
	     *
	     * @param numStack
	     * @return
	     */
	    private int exec(LinkedQueue<String> numStack) {
	        //遇到操作符则弹出栈顶的两个元素
	        if (numStack == null || numStack.size() < 3) {
	            throw new IllegalArgumentException();
	        }
	        Stack<Integer> stack = new Stack<>();
	        String item;
	        while (numStack.size()>0) {
	            item = numStack.removeFirst();
	            if (isDigits(item)) {
	                stack.push(Integer.parseInt(item));
	            }else{
	                Integer b = stack.pop();
	                Integer a = stack.pop();
	                //计算栈顶的两个元素,并将结果压栈
	                stack.push(MathOpt.getOpt(item.charAt(0)).calculate(a, b));
	            }
	        }
	        return stack.pop();
	    }
	
	    private boolean isDigits(String item) {
	        if (item == null || item.trim().equals("")) {
	            return false;
	        }
	        for (int i = 0; i < item.length(); i++) {
	            if (!Character.isDigit(item.charAt(i))) {
	                return false;
	            }
	        }
	        return true;
	    }
	
	    private LinkedQueue<String> mapToNumStack(String expr) {
	        Stack<Character> optStack = new Stack<Character>();
	        LinkedQueue<String> numQueue = new LinkedQueue<String>();
	        //1.从左到右扫描
	        boolean numEnd = false;
	        StringBuilder tempNum = new StringBuilder();
	        for (int i = 0; i < expr.length(); i++) {
	            final char c = expr.charAt(i);
	            if (Character.isDigit(c)) {
	                //2.若读到是操作数,先存在tempNum中
	                tempNum.append(c);
	//                numQueue.addLast(String.valueOf(c));
	            }else{
	                //3.若读到的是运算符
	                //tempNum是否有数字,一并存入【操作数栈】
	                if (tempNum.length()>0) {
	                    numQueue.addLast(tempNum.toString());
	                    tempNum.delete(0, tempNum.length());
	                }
	                MathOpt mathOpt = MathOpt.getOpt(c);
	                dealMathOpt(mathOpt, optStack, numQueue);
	            }
	        }
	        if (tempNum.length()>0) {
	            numQueue.addLast(tempNum.toString());
	            tempNum.delete(0, tempNum.length());
	        }
	
	        //4.当表示读取完成后运算符栈中尚有运算符时,则依序取出运算符到【操作数栈】直到【运算符栈】为空。
	        while (optStack.size() != 0) {
	            numQueue.addLast(String.valueOf(optStack.pop()));
	        }
	        return numQueue;
	    }
	
	    private void dealMathOpt(MathOpt currentMathOpt, final Stack<Character> optStack, final LinkedQueue<String> numQueue) {
	        if (currentMathOpt == null || optStack == null || numQueue == null) {
	            throw new NullPointerException();
	        }
	        //3.若读到的是运算符
	        Character headOptChar = optStack.peek();
	        MathOpt headMathOpt = headOptChar==null?null: MathOpt.getOpt(headOptChar);
	        if(currentMathOpt.priority == Priority.HIGH){//括号运算符
	            if (currentMathOpt == MathOpt.LEFT_BRACKET) {
	                //3.1 若为左括号“(”,则直接存入【运算符栈】
	                optStack.push(currentMathOpt.opt);
	            }else{
	                //3.2 若为右括号“)”,则输出【运算符栈】的运算符,直到遇到左括号为止,此时抛弃该左括号。
	                while (true) {
	                    Character nextOptChar = optStack.peek();
	                    if (nextOptChar == null) {
	                        throw new IllegalArgumentException("缺少左括号");
	                    }
	                    MathOpt nextHeadMathOpt = MathOpt.getOpt(nextOptChar);
	                    if (nextHeadMathOpt.equals(MathOpt.LEFT_BRACKET)) {
	                        //栈顶为左括号 ,丢弃
	                        optStack.pop();
	                        break;
	                    }
	                    numQueue.addLast(String.valueOf(optStack.pop()));
	                }
	            }
	        }else {//非括号运算符
	            if (headMathOpt!=null && MathOpt.LEFT_BRACKET.opt == headMathOpt.opt) {
	                //a.若【运算符栈】栈顶的运算符为左括号,则直接存入【运算符栈】
	                optStack.push(currentMathOpt.opt);
	            } else if (headMathOpt==null||currentMathOpt.priority.ordinal()> headMathOpt.priority.ordinal()) {
	                //b.若比【运算符栈】栈顶的运算符优先级高,则直接存入【运算符栈】。
	                optStack.push(currentMathOpt.opt);
	            } else  {
	                // ps:从【运算符】栈顶依次弹出所有【高于或等于】当前运算符的运算符,遇到左括号或低于该当前运算符的则停止。
	                //c.若比【运算符栈】栈顶的运算符优先级低或相等,则输出栈顶运算符到【操作数栈】,
	                // 直到【运算符栈】栈顶运算符低于(不包括等于)该运算符优先级或为左括号,并将当前运算符压入【运算符栈】
	                numQueue.addLast(String.valueOf(optStack.pop()));
	                while (true) {
	                    Character nextOptChar = optStack.peek();
	                    if (nextOptChar == null) {
	                        //栈顶已经不存在运算,将当前运算法压入【运算符栈】
	                        optStack.push(currentMathOpt.opt);
	                       break;
	                    }
	                    MathOpt nextHeadMathOpt = MathOpt.getOpt(nextOptChar);
	
	                    if (nextHeadMathOpt.equals(MathOpt.LEFT_BRACKET)) {
	                        //栈顶为左括号 ,停止
	                        //当前运算法压入【运算符栈】
	                        optStack.push(currentMathOpt.opt);
	                        break;
	                    }else if(currentMathOpt.priority.ordinal() <= nextHeadMathOpt.priority.ordinal()){
	                        //比栈顶运算符小的,输出到【操作数栈】
	                        numQueue.addLast(String.valueOf(optStack.pop()));
	                    }else{
	                        //比栈顶运算符大的,将当前运算符压入【运算符栈】,并退出
	                        optStack.push(currentMathOpt.opt);
	                        break;
	                    }
	                }
	            }
	
	        }
	
	    }
	
	    enum MathOpt {
	        ADD(Priority.LOW, '+'){
	            @Override
	            int calculate(int a, int b) {
	                return a+b;
	            }
	        },MINUS(Priority.LOW,'-')
	            {
	                @Override
	                int calculate(int a, int b) {
	                    return a-b;
	                }
	            },MULTI(Priority.MIDDLE,'*')
	            {
	                @Override
	                int calculate(int a, int b) {
	                    return a*b;
	                }
	            },DIV(Priority.MIDDLE,'/'){
	            @Override
	            int calculate(int a, int b) {
	                return a/b;
	            }
	        },
	        LEFT_BRACKET(Priority.HIGH, '('){
	            @Override
	            int calculate(int a, int b) {
	                throw new IllegalArgumentException();
	            }
	        }, RIGHT_BRACKET(Priority.HIGH, ')'){
	            @Override
	            int calculate(int a, int b) {
	                throw new IllegalArgumentException();
	            }
	        },;
	        private final Priority priority;
	        private final char opt;
	        MathOpt(Priority priority, char opt) {
	            this.priority=priority;
	            this.opt = opt;
	        }
	
	        static MathOpt getOpt(char opt) {
	            for (MathOpt mathOpt : MathOpt.values()) {
	                if (mathOpt.opt == opt) {
	                    return mathOpt;
	                }
	            }
	            return null;
	        }
	
	        abstract int calculate(int a, int b);
	
	    }
	    enum Priority{
	        LOW(),MIDDLE(),HIGH();
	//        LOW(1),MIDDLE(2),HIGH(3);
	//        private final int level;
	//        Priority(int i) {
	//            this.level = i;
	//        }
	    }
	
	    static class  LinkedQueue<E> {
	
	        private Stack.Node<E> head;
	        private Stack.Node<E> tail;
	        private int count=0;
	        private static class Node<E> {
	            E data;
	            Stack.Node<E> prev;
	            Stack.Node<E> next;
	            public Node(E data, Stack.Node<E> prev, Stack.Node<E> next) {
	                this.data = data;
	                this.prev = prev;
	                this.next = next;
	            }
	            @Override
	            public String toString() {
	                final StringBuilder sb = new StringBuilder("{");
	                sb.append("\"data\":")
	                    .append(data);
	                sb.append(",\"prev\":")
	                    .append(prev);
	                sb.append(",\"next\":")
	                    .append(next);
	                sb.append('}');
	                return sb.toString();
	            }
	        }
	
	        public <E> LinkedQueue() {
	        }
	
	        public void addLast(E e) {
	            if (tail == null) {
	                head = tail = new Stack.Node<>(e, null, null);
	            }else{
	                Stack.Node<E> node = new Stack.Node<>(e, null, null);
	                tail.next=node;
	                node.prev = tail;
	                tail = node;
	            }
	            count++;
	        }
	
	        public E removeFirst() {
	            checkNotEmpty();
	            final Stack.Node<E> headNode = this.head;
	            final E data = headNode.data;
	            Stack.Node<E> next = head.next;
	            head=next;
	            count--;
	            //help gc
	            if(next!=null)next.prev=null;
	            headNode.data=null;
	            headNode.next=null;
	            return data;
	        }
	
	        private void checkNotEmpty() {
	            if (count == 0) {
	                throw new NoSuchElementException();
	            }
	        }
	
	        public int size(){
	            return count;
	        }
	
	        @Override
	        public String toString() {
	            final StringBuilder sb = new StringBuilder("{");
	            sb.append("size: ").append(size()).append(",data:[");
	            Stack.Node<E> node = head;
	            while (node != null) {
	                sb.append(node.data);
	                node = node.next;
	                if (node == null) {
	                    break;
	                }
	                sb.append(",");
	            }
	            sb.append("]}");
	            return sb.toString();
	        }
	    }
	    
	    public static void main(String[] args) {
	        LinkedQueue<Integer> queue = new LinkedQueue<>();
	        queue.addLast(3);
	        queue.addLast(4);
	        queue.addLast(5);
	//        queue.addLast(7);//exception
	        System.out.println(queue);
	        System.out.println(queue.removeFirst());
	        System.out.println(queue);
	        System.out.println(queue.removeFirst());
	        System.out.println(queue);
	        System.out.println(queue.removeFirst());
	        System.out.println(queue);
	//        System.out.println(queue.removeFirst());//exception
	//        System.out.println(queue);
	
	        //test stack
	        Stack<Integer> stack = new Stack<>();
	        stack.push(1);
	        stack.push(2);
	        stack.push(3);
	//        stack.push(4);//
	        System.out.println(stack);
	        System.out.println(stack.peek());
	        System.out.println(stack.pop());
	        System.out.println(stack);
	        System.out.println(stack.pop());
	        System.out.println(stack);
	        System.out.println(stack.pop());
	        System.out.println(stack);
	//        System.out.println(stack.pop());//exception
	
	        System.out.println(new MathOperation2().calculate("9+(3-1)*3+10/2")==9+(3-1)*3+10/2);
	        System.out.println(new MathOperation2().calculate("(1+2)*3-4*5/2")==(1+2)*3-4*5/2);
	        System.out.println(new MathOperation2().calculate("(1+2)*(5*(3-4)*2)*5/4")==(1+2)*(5*(3-4)*2)*5/4);
	
	    }
	
	    /**
	     * 先进后出
	     * @param <E>
	     */
	    static class Stack<E>{
	
	        private Node<E> head;
	        private Node<E> tail;
	        private int count=0;
	//        private int capacity;
	        private static class Node<E>{
	            E data;
	            Node<E> prev;
	            Node<E> next;
	            public Node(E data,Node<E> prev, Node<E> next) {
	                this.data = data;
	                this.prev = prev;
	                this.next = next;
	            }
	            @Override
	            public String toString() {
	                final StringBuilder sb = new StringBuilder("{");
	                sb.append("\"data\":")
	                    .append(data);
	                sb.append(",\"prev\":")
	                    .append(prev);
	                sb.append(",\"next\":")
	                    .append(next);
	                sb.append('}');
	                return sb.toString();
	            }
	        }
	
	        public Stack() {
	        }
	
	        public void push(E e) {
	//            checkNotFull();
	            count ++;
	            if (tail == null) {
	                head = tail = new Node<>(e,null, null);
	            }else{
	                Node<E> node = new Node<>(e, null, null);
	                tail.next = node;
	                node.prev = tail;
	                //newNode become tail Node
	                tail = node;
	            }
	        }
	
	//        private void checkNotFull() {
	//            if(count==capacity)throw new IndexOutOfBoundsException();
	//        }
	        private void checkNotEmpty() {
	            if(count==0) throw new NoSuchElementException();
	        }
	
	        public E peek() {
	            return tail==null?null:tail.data;
	        }
	
	        public E pop() {
	            checkNotEmpty();
	            final Node<E> tailNode = tail;
	            Node<E> prev = tailNode.prev;
	            final E data = tailNode.data;
	
	            tailNode.prev = null;
	            if (prev == null) {
	                //tailNode is headNode
	                head = null;
	            } else {
	                prev.next = null;
	            }
	            //help gc
	            tailNode.prev = null;
	            tailNode.data = null;
	
	            tail = prev;
	            count--;
	            return data;
	        }
	
	        public int size(){
	            return count;
	        }
	
	        @Override
	        public String toString() {
	            final StringBuilder sb = new StringBuilder("{");
	            sb.append("size:").append(count).append(",data:[");
	            Node<E> node = head;
	            while (node!=null) {
	                sb.append(node.data);
	                node=node.next;
	                if (node == null) {
	                    break;
	                }
	                sb.append(",");
	            }
	            sb.append("]}");
	            return sb.toString();
	        }
	    }
	}
posted @ 2019-07-10 14:42  thewindkee  阅读(206)  评论(0编辑  收藏  举报