棧應用-中綴表達式轉後綴表達式並計算值

表達式的三種形式:
中綴表達式:運算符放在兩個運算對象中間,如:(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();
	        }
	    }
	}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章