Stack of Java Data Structures

Keywords: PHP Java calculator less

1. Introduction to Stack

The stack is an ordered list of FILO:First In Last Out.

Stack is a special linear table that limits the insertion and deletion of elements in a linear table to only occur at the same end.

One end that allows insertion and deletion is called the top of the stack and the other end is the fixed end, called the bottom of the stack.

Depending on the definition of the stack, elements first placed on the stack are at the bottom of the stack, and elements last placed on the top of the stack

Deleting an element is the opposite. The last element put in is deleted first, the first element put in is deleted last

2. Stack illustration

3. Stack out illustration

4. Scenarios

1) Call of a subprogram: Before jumping to a subprogram, the address of the next instruction will be stored on the stack until the subprogram is executed before taking out the address to return to the original program.

2) Processing recursive calls: Similar to the call of a subroutine, except that in addition to the address where the next instruction is stored, data such as parameters, region variables, and so on are stored on the stack.

3) Conversion of expression [suffix expression to suffix expression] and evaluation (actual solution).

4) Traversal of binary trees.

5) Graphic depth-first search method.

5. Simulate stack with array

Ideas:

1) Define a top to represent the top of the stack, initialized to -1

2) stacking operation, when data is added to the stack, top+; stack[top] = data;

3) Out of stack operation, int value = stack[top]; top--; return value;

Code implementation:

//Define a ArrayStack Representation stack
class ArrayStack {
    private int maxSize; // Stack size
    private int[] stack; // Array, array simulation stack, where the data is placed
    private int top = -1;// top Represents the top of the stack, initialized to-1
    
    //constructor
    public ArrayStack(int maxSize) {
        this.maxSize = maxSize;
        stack = new int[this.maxSize];
    }
    
    //Full stack
    public boolean isFull() {
        return top == maxSize - 1;
    }
    //Stack empty
    public boolean isEmpty() {
        return top == -1;
    }
    //Push-push
    public void push(int value) {
        //First determine if the stack is full
        if(isFull()) {
            System.out.println("Full stack");
            return;
        }
        top++;
        stack[top] = value;
    }
    //Stack Out-pop, Return data from top of stack
    public int pop() {
        //First determine if the stack is empty
        if(isEmpty()) {
            //throw
            throw new RuntimeException("Stack empty, no data~");
        }
        int value = stack[top];
        top--;
        return value;
    }
    //Show the stack[Traverse Stack], During traversal, data needs to be displayed from the top of the stack
    public void list() {
        if(isEmpty()) {
            System.out.println("Stack empty, no data~~");
            return;
        }
        //Data needs to be displayed from the top of the stack
        for(int i = top; i >= 0 ; i--) {
            System.out.printf("stack[%d]=%d\n", i, stack[i]);
        }
    }
}

6. Stack implements infix expression evaluator

Infix expressions are common operations, such as (3+4) *5-6

public class Calculator {

    public static void main(String[] args) {
        //Complete the expression according to the previous teacher's ideas
        String expression = "7*2*2-5+1-5+3-4"; // 15//How to deal with multidigit problems?
        //Create two stacks, a number stack, a symbol stack
        ArrayStack2 numStack = new ArrayStack2(10);
        ArrayStack2 operStack = new ArrayStack2(10);
        //Define the required related variables
        int index = 0;//For Scanning
        int num1 = 0; 
        int num2 = 0;
        int oper = 0;
        int res = 0;
        char ch = ' '; //Get every scan char Save to ch
        String keepNum = ""; //For splicing multiple digits
        //start while Cyclic Scan expression
        while(true) {
            //Get in turn expression Every character
            ch = expression.substring(index, index+1).charAt(0);
            //judge ch What is, and then do the appropriate processing
            if(operStack.isOper(ch)) {//If it is an operator
                //Determine if the current symbol stack is empty
                if(!operStack.isEmpty()) {
                    //Compare if symbol stack has operators,If the priority of the current operator is less than or equal to the operator in the stack,From the stack of numbers pop Out two numbers,
                    //In From Symbol Stack pop Out a symbol, perform the operation, and the result is put on the stack of numbers, then the current operator is put on the stack of symbols
                    if(operStack.priority(ch) <= operStack.priority(operStack.peek())) {
                        num1 = numStack.pop();
                        num2 = numStack.pop();
                        oper = operStack.pop();
                        res = numStack.cal(num1, num2, oper);
                        //The result of an operation is like a stack of numbers
                        numStack.push(res);
                        //Then put the current operator on the symbol stack
                        operStack.push(ch);
                    } else {
                        //If the priority of the current operator is greater than that of the operator in the stack, it goes directly to the symbol stack.
                        operStack.push(ch);
                    }
                }else {
                    //If empty, go directly to the symbol stack..
                    operStack.push(ch); // 1 + 3
                }
            } else { //If it is a number, go directly to the number stack
                
                //numStack.push(ch - 48); //? "1+3" '1' => 1
                //Analysis ideas
                //1. When dealing with multidigits, you can't find a number and immediately stack it because it may be multidigits
                //2. In the number of processes, you need to expression Expressive index See one more later,Scan for numbers and stack for symbols
                //3. So we need to define a variable string for splicing
                
                //Processing multi-digit
                keepNum += ch;
                
                //If ch Already expression The last one, go directly to the stack
                if (index == expression.length() - 1) {
                    numStack.push(Integer.parseInt(keepNum));
                }else{
                
                    //Determines whether the next character is a number, continues scanning if it is a number, and stacks if it is an operator
                    //Notice that the latter one, not the other index++
                    if (operStack.isOper(expression.substring(index+1,index+2).charAt(0))) {
                        //If the latter bit is an operator, stack keepNum = "1" perhaps "123"
                        numStack.push(Integer.parseInt(keepNum));
                        //Important!!!!!!, keepNum empty
                        keepNum = "";
                        
                    }
                }
            }
            //Give Way index + 1, And determine whether to scan to expression Last.
            index++;
            if (index >= expression.length()) {
                break;
            }
        }
        
        //When the expression is scanned, the order is from the stack of numbers and symbols pop Number and symbol, and run.
        while(true) {
            //If the symbol stack is empty, the final result is calculated, There is only one number in the stack [Result]
            if(operStack.isEmpty()) {
                break;
            }
            num1 = numStack.pop();
            num2 = numStack.pop();
            oper = operStack.pop();
            res = numStack.cal(num1, num2, oper);
            numStack.push(res);//Push
        }
        //The last number of stacks, pop Out is the result
        int res2 = numStack.pop();
        System.out.printf("Expression %s = %d", expression, res2);
    }

}

//Create a stack first,Create directly using the previous
//Define a ArrayStack2 Representation stack, Require extended functionality
class ArrayStack2 {
    private int maxSize; // Stack size
    private int[] stack; // Array, array simulation stack, where the data is placed
    private int top = -1;// top Represents the top of the stack, initialized to-1
    
    //constructor
    public ArrayStack2(int maxSize) {
        this.maxSize = maxSize;
        stack = new int[this.maxSize];
    }
    
    //Add a method that returns the value at the top of the current stack, But it's not real pop
    public int peek() {
        return stack[top];
    }
    
    //Full stack
    public boolean isFull() {
        return top == maxSize - 1;
    }
    //Stack empty
    public boolean isEmpty() {
        return top == -1;
    }
    //Push-push
    public void push(int value) {
        //First determine if the stack is full
        if(isFull()) {
            System.out.println("Full stack");
            return;
        }
        top++;
        stack[top] = value;
    }
    //Stack Out-pop, Return data from top of stack
    public int pop() {
        //First determine if the stack is empty
        if(isEmpty()) {
            //throw
            throw new RuntimeException("Stack empty, no data~");
        }
        int value = stack[top];
        top--;
        return value;
    }
    //Show the stack[Traverse Stack], During traversal, data needs to be displayed from the top of the stack
    public void list() {
        if(isEmpty()) {
            System.out.println("Stack empty, no data~~");
            return;
        }
        //Data needs to be displayed from the top of the stack
        for(int i = top; i >= 0 ; i--) {
            System.out.printf("stack[%d]=%d\n", i, stack[i]);
        }
    }
    //Returns the priority of the operator, which is determined by the programmer, Priorities are represented by numbers
    //The larger the number, the higher the priority.
    public int priority(int oper) {
        if(oper == '*' || oper == '/'){
            return 1;
        } else if (oper == '+' || oper == '-') {
            return 0;
        } else {
            return -1; // Assume that the current expression only has +, - , * , /
        }
    }
    //Determine if it is an operator
    public boolean isOper(char val) {
        return val == '+' || val == '-' || val == '*' || val == '/';
    }
    //computing method
    public int cal(int num1, int num2, int oper) {
        int res = 0; // res Used to store the results of calculations
        switch (oper) {
        case '+':
            res = num1 + num2;
            break;
        case '-':
            res = num2 - num1;// Attention order
            break;
        case '*':
            res = num1 * num2;
            break;
        case '/':
            res = num2 / num1;
            break;
        default:
            break;
        }
        return res;
    }
}

7. Stack implementation suffix expression (inverse Poland) calculator

The evaluation of a suffix expression is the most familiar to us, but it is not easy for a computer to operate on. Therefore, when calculating the result, the suffix expression will often be converted to another expression to operate on (usually to a suffix expression)

A suffix expression, also known as an inverse Polish expression, is similar to a prefix expression except that the operator follows the operand, for example: (3+4)*5-6 The corresponding suffix expression is 34+5*6-

Another example is:

1) Computer evaluation of suffix expressions

Scan the expression from left to right, push the number into the stack when it encounters a number, pop up two numbers at the top of the stack when it encounters an operator, calculate them accordingly with the operator (the next top element and the top element of the stack), and put the result on the stack; repeat the process until the rightmost end of the expression, and the final value is the expressionResult of formula

For example, (3+4)*5-6 corresponds to a suffix expression of 34+5*6 -, and the evaluation steps for the suffix expression are as follows:

(1) Scan from left to right and press 3 and 4 onto the stack;

(2) Encountered the + operator, so pop up 4 and 3 (4 is the top element, 3 is the second top element), calculate the value of 3+4, get 7, and then put 7 on the stack;

(3) putting 5 on the stack;

(4) Next is the * operator, so pop up 5 and 7, calculate 7 * 5 = 35, put 35 on the stack;

(5) putting 6 on the stack;

(6) Finally, the -operator calculates the value of 35-6, which is 29, and the final result is obtained.

code implementation

//Complete the operation of the inverse Polish expression
/*
 * 1)Scan from left to right to push 3 and 4 onto the stack;
    2)Encountered the + operator, so pop up 4 and 3 (4 is the top element, 3 is the second top element), calculate the value of 3+4, get 7, and put 7 on the stack;
    3)Put 5 on the stack;
    4)Next is the * operator, so pop up 5 and 7, calculate 7 * 5 = 35, put 35 on the stack;
    5)Put 6 on the stack;
    6)The final result is the -operator, which calculates the value of 35-6, or 29.
 */
public static int calculate(List<String> ls) {
    // Create to Stack, Just one stack is needed
    Stack<String> stack = new Stack<String>();
    // ergodic ls
    for (String item : ls) {
        // Use regular expressions to take out numbers here
        if (item.matches("\\d+")) { // Multiple digits matched
            // Push
            stack.push(item);
        } else {
            // pop Out two numbers, combine them, and put them on the stack
            int num2 = Integer.parseInt(stack.pop());
            int num1 = Integer.parseInt(stack.pop());
            int res = 0;
            if (item.equals("+")) {
                res = num1 + num2;
            } else if (item.equals("-")) {
                res = num1 - num2;
            } else if (item.equals("*")) {
                res = num1 * num2;
            } else if (item.equals("/")) {
                res = num1 / num2;
            } else {
                throw new RuntimeException("Error in operator");
            }
            //hold res Push
            stack.push("" + res);
        }
    }
    //Last stayed stack The data in is the result of the operation
    return Integer.parseInt(stack.pop());
}

2) Infix expression to suffix expression

The steps are as follows:

(1) Initialize two stacks: operator stack s 1 and stack s2 storing intermediate results;

(2) Scan the infix expression from left to right;

(3) when an operand is encountered, it is pressed s2;

(4) When encountering an operator, compare it with the top operator of the s1 stack:

(4-1) If s1 is empty or the top of the stack operator is the left parenthesis'('), the operator is directly stacked;

(4-2) Otherwise, if the priority is higher than the top of the stack operator, the operator will also be pushed into s1;

(4-3) Otherwise, eject the operator at the top of the S1 stack and press it into s2, then go to (4-1) again to compare with the new top operator in s1;

(5) When encountering brackets:

(5-1) If left parenthesis'('), press s1 directly

(5-2) If the right parenthesis is')', pop up the operator at the top of the s1 stack one by one and press into s2 until the left parenthesis is encountered, discarding the pair of parentheses at this point

(6) Repeat steps 2 to 5 until the rightmost side of the expression

(7) Pop out the remaining operators in s1 and press them into s2 in turn

(8) Pop out the elements in s2 one by one and output them. The reverse order of the results is the suffix expression corresponding to the infix expression.

For example, the process of converting the infix expression "1+((2+3)*4) -5" to a suffix expression is as follows:

Code implementation:

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

public class PolandNotation {

    public static void main(String[] args) {
        
        
        //Completes the function of converting a suffix expression to a suffix expression
        //Explain
        //1. 1+((2+3)×4)-5 => Convert to 1 2 3 + 4 × + 5 –
        //2. Because it's directly against str The operation is inconvenient, so the first step is to  "1+((2+3)×4)-5" => The expression corresponding to the infix List
        //   That is "1+((2+3)×4)-5" => ArrayList [1,+,(,(,2,+,3,),*,4,),-,5]
        //3. Corresponds to the resulting infix expression List => Corresponding to the suffix expression List
        //   That is ArrayList [1,+,(,(,2,+,3,),*,4,),-,5]  => ArrayList [1,2,3,+,4,*,+,5,–]
        
        String expression = "1+((2+3)*4)-5";//Notice the expression 
        List<String> infixExpressionList = toInfixExpressionList(expression);
        System.out.println("Corresponding to infix expression List=" + infixExpressionList); // ArrayList [1,+,(,(,2,+,3,),*,4,),-,5]
        List<String> suffixExpreesionList = parseSuffixExpreesionList(infixExpressionList);
        System.out.println("Corresponding to the suffix expression List" + suffixExpreesionList); //ArrayList [1,2,3,+,4,*,+,5,–] 
        
        System.out.printf("expression=%d", calculate(suffixExpreesionList)); // ?
        
        /*
        
        //Define first to the inverse Polish expression
        //(30+4)×5-6  => 30 4 + 5 × 6 - => 164
        // 4 * 5 - 8 + 60 + 8 / 2 => 4 5 * 8 - 60 + 8 2 / + 
        //test 
        //Explain that for convenience, the numbers and symbols of the inverse Polish expression are separated by spaces
        //String suffixExpression = "30 4 + 5 * 6 -";
        String suffixExpression = "4 5 * 8 - 60 + 8 2 / +"; // 76
        //thinking
        //1. Put "34 + 5 x 6 -" => in ArrayList first
        //2. Pass an ArrayList to a method, traverse the ArrayList with the stack to complete the calculation
        
        List<String> list = getListString(suffixExpression);
        System.out.println("rpnList=" + list);
        int res = calculate(list);
        System.out.println("The result of the calculation is = "+ res";
        
        */
    }
    
    //That is ArrayList [1,+,(,(,2,+,3,),*,4,),-,5]  => ArrayList [1,2,3,+,4,*,+,5,–]
    //Method: The resulting infix expression corresponds to the List => Corresponding to the suffix expression List
    public static List<String> parseSuffixExpreesionList(List<String> ls) {
        //Define two stacks
        Stack<String> s1 = new Stack<String>(); // Symbol stack
        //Description: Because s2 This stack, during the entire conversion process, does not have pop Operation, and we need to reverse the order later
        //So it's cumbersome, we don't need it here Stack<String> Direct use List<String> s2
        //Stack<String> s2 = new Stack<String>(); // Stack for storing intermediate results s2
        List<String> s2 = new ArrayList<String>(); // Storing intermediate results Lists2
        
        //ergodic ls
        for(String item: ls) {
            //If it's a number, join s2
            if(item.matches("\\d+")) {
                s2.add(item);
            } else if (item.equals("(")) {
                s1.push(item);
            } else if (item.equals(")")) {
                //If it is a right parenthesis)",Pop-up in turn s1 Operator at the top of the stack and pushes in s2,Discard the pair until you encounter the left parenthesis
                while(!s1.peek().equals("(")) {
                    s2.add(s1.pop());
                }
                s1.pop();//!!! take ( Eject s1 Stack, remove parentheses
            } else {
                //When item Priority is less than or equal to s1 Top Stack Operator, take s1 Operators at the top of the stack pop up and join s2 Medium, go to again(4.1)and s1 New stack top operator comparison in
                //Problem: We lack a way to compare priorities
                while(s1.size() != 0 && Operation.getValue(s1.peek()) >= Operation.getValue(item) ) {
                    s2.add(s1.pop());
                }
                //You will also need to item Push on Stack
                s1.push(item);
            }
        }
        
        //take s1 The remaining operators in the pop-up and join in turn s2
        while(s1.size() != 0) {
            s2.add(s1.pop());
        }

        return s2; //Note because it is stored in List, So the sequential output corresponds to the corresponding suffix expression List
        
    }
    
    //Method: Convert the infix expression to the corresponding List
    //  s="1+((2+3)×4)-5";
    public static List<String> toInfixExpressionList(String s) {
        //Define a List,Stores the contents of the infix expression
        List<String> ls = new ArrayList<String>();
        int i = 0; //This is a pointer that traverses the infix expression string
        String str; // Stitching of multiple digits
        char c; // Every character traversed, it is placed in the c
        do {
            //If c Is a non-number, I need to join ls
            if((c=s.charAt(i)) < 48 ||  (c=s.charAt(i)) > 57) {
                ls.add("" + c);
                i++; //i Need to move back
            } else { //If it is a number, consider multiple digits
                str = ""; //First put str Set up"" '0'[48]->'9'[57]
                while(i < s.length() && (c=s.charAt(i)) >= 48 && (c=s.charAt(i)) <= 57) {
                    str += c;//Stitching
                    i++;
                }
                ls.add(str);
            }
        }while(i < s.length());
        return ls;//Return
    }
    
    //Put an inverse Polish expression, data and operators in turn ArrayList in
    public static List<String> getListString(String suffixExpression) {
        //take suffixExpression Division
        String[] split = suffixExpression.split(" ");
        List<String> list = new ArrayList<String>();
        for(String ele: split) {
            list.add(ele);
        }
        return list;
        
    }
    
    //Complete the operation of the inverse Polish expression
    /*
     * 1)Scan from left to right to push 3 and 4 onto the stack;
        2)Encountered the + operator, so pop up 4 and 3 (4 is the top element, 3 is the second top element), calculate the value of 3+4, get 7, and put 7 on the stack;
        3)Put 5 on the stack;
        4)Next is the * operator, so pop up 5 and 7, calculate 7 * 5 = 35, put 35 on the stack;
        5)Put 6 on the stack;
        6)The final result is the -operator, which calculates the value of 35-6, or 29.
     */

    public static int calculate(List<String> ls) {
        // Create to Stack, Just one stack is needed
        Stack<String> stack = new Stack<String>();
        // ergodic ls
        for (String item : ls) {
            // Use regular expressions to take out numbers here
            if (item.matches("\\d+")) { // Multiple digits matched
                // Push
                stack.push(item);
            } else {
                // pop Out two numbers, combine them, and put them on the stack
                int num2 = Integer.parseInt(stack.pop());
                int num1 = Integer.parseInt(stack.pop());
                int res = 0;
                if (item.equals("+")) {
                    res = num1 + num2;
                } else if (item.equals("-")) {
                    res = num1 - num2;
                } else if (item.equals("*")) {
                    res = num1 * num2;
                } else if (item.equals("/")) {
                    res = num1 / num2;
                } else {
                    throw new RuntimeException("Error in operator");
                }
                //hold res Push
                stack.push("" + res);
            }
            
        }
        //Last stayed stack The data in is the result of the operation
        return Integer.parseInt(stack.pop());
    }
}

//Write a class Operation You can return the priority corresponding to an operator
class Operation {
    private static int ADD = 1;
    private static int SUB = 1;
    private static int MUL = 2;
    private static int DIV = 2;
    
    //Write a method that returns the corresponding priority number
    public static int getValue(String operation) {
        int result = 0;
        switch (operation) {
        case "+":
            result = ADD;
            break;
        case "-":
            result = SUB;
            break;
        case "*":
            result = MUL;
            break;
        case "/":
            result = DIV;
            break;
        default:
            System.out.println("The operator does not exist" + operation);
            break;
        }
        return result;
    }
}

Posted by Lassie on Wed, 24 Jul 2019 09:49:04 -0700