What is a stack? How does Java implement integrated calculator through stack?

Introduction to stack

A stack is a first in, then out, ordered list. Stack is a special linear table that restricts the insertion and deletion of elements in a linear table to the same end of the linear table. The end that allows insertion and deletion is the changing end, which becomes the Top of the stack, and the other end is the fixed end, which becomes the bottom of the stack. According to the definition of stack, the elements put into the stack first are at the bottom of the stack. The last placed element is at the Top of the stack, while the deleted element is just the opposite. The last placed element is deleted first, and the first placed element is deleted last.

Application scenario of stack

  1. Subroutine call: before jumping to the subroutine, the address of the next instruction will be stored in the stack until the subroutine is executed, and then the address will be taken out to return to the original program.

  2. Handling recursive calls: similar to subroutine calls, except that in addition to storing the address of the next instruction, parameters, area variables and other data are also stored in the stack.

  3. Conversion and evaluation of expressions (infix expression to suffix expression)

  4. Traversal of binary tree

  5. The depth first search method of graphics.

Quick start to stack

Use the array to simulate the use of the stack. Since the stack is an ordered list, of course, the structure of the array can be used to store the data content of the stack. Next, we will use the data to simulate the operations such as out of the stack and in the stack.

Thought analysis of realizing stack

  1. Use arrays to simulate stacks
  2. Define a top to represent the top of the stack and initialize it to - 1
  3. When data is added to the stack, top++;stack[top] = data;
  4. Stack out operation, int value = stack[top];top–,return value

code implementation

  1. Create an ArrayStackDomo exercise class

  1. Define an ArrayStack to represent the stack
	class ArrayStack{
        private int maxSize;  //Stack size
        private int[] stack;  //Array, array simulation stack, data is placed in the array
        private int top = -1; //Top indicates the top of the stack. Initialization to - 1 indicates no data
	}
  1. Write constructor
   public ArrayStack(int maxSize){
        this.maxSize =maxSize;
        stack = new int[this.maxSize];
	}
  1. Judge stack full
 	public boolean isFull(){
       return top == maxSize - 1; //When the top of the stack is equal to the size of the stack, it indicates that the stack is full
    }
  1. Judge whether the stack is empty
  public boolean isEmpty(){
      return top == -1;
  }
  1. Write the push method
        public void push(int value){
            //Determine whether the stack is full
            if (isFull()){
                System.out.println("Stack full");
                return;
            }
            top++;
            stack[top] = value;
        }
  1. Write the stack method pop to return the data at the top of the stack
        public int pop(){
            //First judge whether the stack is empty
            if (isEmpty()){
                //Throw exception
                throw new RuntimeException("Stack empty,no data~");
            }
            int value = stack[top];
            top--;
            return value;
        }
  1. Write the case of the display stack [traversing the stack]. When convenient, you need to display data from the top of the stack.
        public void list(){
            if (isEmpty()){
                System.out.println("Stack empty, no data~~");
                return;
            }

            for(int i = top; i >= 0; i--){
                System.out.printf("stack[%d]=%d\n",i,stack[i]);
            }
        }

test

    public static void main(String[] args) {
        //Test whether ArrayStack is correct
        //First create an ArrayStack object - > represent stack
        ArrayStack stack = new ArrayStack(4);
        String key ="";
        boolean loop =true;//Controls whether to exit the menu
        Scanner scanner =new Scanner(System.in);

        while (loop){
            System.out.println("show: Indicates the display stack");
            System.out.println("exit: Exit program");
            System.out.println("push: Indicates adding data to the stack(Push )");
            System.out.println("pop: Indicates fetching data from the stack(Out of stack)");
            System.out.print("Please enter your choice:");
            key=scanner.next();
            switch (key){
                case "show":
                    stack.list();
                    break;
                case "exit":
                    scanner.close();
                    loop=false;
                    break;
                case "push":
                    System.out.print("Please enter a number:");
                    int value = scanner.nextInt();
                    stack.push(value);
                    break;
                case "pop":
                    try {
                        int res = stack.pop();
                        System.out.printf("The data out of the stack is%d\n",res);
                    }catch (Exception e){
                        System.out.println(e.getMessage());
                    }
                    break;
                default:
                    break;
            }
            System.out.println("---------------------------------");
        }
        System.out.println("The program has exited");
    }
  1. Stack test

  1. Test display stack

  1. Test out stack

Complete code

import java.util.Scanner;

/**
 * @author mengzhichao
 * @create 2022-04-15-16:28
 */
public class ArrayStackDemo {

    public static void main(String[] args) {
        //Test whether ArrayStack is correct
        //First create an ArrayStack object - > represent stack
        ArrayStack stack = new ArrayStack(4);
        String key ="";
        boolean loop =true;//Controls whether to exit the menu
        Scanner scanner =new Scanner(System.in);

        while (loop){
            System.out.println("show: Indicates the display stack");
            System.out.println("exit: Exit program");
            System.out.println("push: Indicates adding data to the stack(Push )");
            System.out.println("pop: Indicates fetching data from the stack(Out of stack)");
            System.out.print("Please enter your choice:");
            key=scanner.next();
            switch (key){
                case "show":
                    stack.list();
                    break;
                case "exit":
                    scanner.close();
                    loop=false;
                    break;
                case "push":
                    System.out.print("Please enter a number:");
                    int value = scanner.nextInt();
                    stack.push(value);
                    break;
                case "pop":
                    try {
                        int res = stack.pop();
                        System.out.printf("The data out of the stack is%d\n",res);
                    }catch (Exception e){
                        System.out.println(e.getMessage());
                    }
                    break;
                default:
                    break;
            }
            System.out.println("---------------------------------");
        }
        System.out.println("The program has exited");
    }
}

    //Define an ArrayStack to represent the stack
    class ArrayStack{
        private int maxSize;  //Stack size
        private int[] stack;  //Array, array simulation stack, data is placed in the array
        private int top = -1; //Top indicates the top of the stack. Initialization to - 1 indicates no data

        //constructor 
        public ArrayStack(int maxSize){
            this.maxSize =maxSize;
            stack = new int[this.maxSize];
        }

        //Stack full
        public boolean isFull(){
            return top == maxSize - 1; //When the top of the stack is equal to the size of the stack, it indicates that the stack is full
        }

        //Stack empty
        public boolean isEmpty(){
            return top == -1;
        }

        //Stack push
        public void push(int value){
            //Determine whether the stack is full
            if (isFull()){
                System.out.println("Stack full");
                return;
            }
            top++;
            stack[top] = value;
        }

        //Out of stack - pop to return the data at the top of the stack
        public int pop(){
            //First judge whether the stack is empty
            if (isEmpty()){
                //Throw exception
                throw new RuntimeException("Stack empty,no data~");
            }
            int value = stack[top];
            top--;
            return value;
        }

        //Display the stack [convenience stack]. When traversing, you need to display data from the top of the stack
        public void list(){
            if (isEmpty()){
                System.out.println("Stack empty, no data~~");
                return;
            }

            for(int i = top; i >= 0; i--){
                System.out.printf("stack[%d]=%d\n",i,stack[i]);
            }
        }


    }

A practical requirement of stack

Suppose we enter a string of expressions. How does the computer get the result? What if it is implemented by stack?

7 + 2 ∗ 6 − 4 7+2*6-4 7+2∗6−4

Calculation idea of using stack to complete expression

  1. Traverse our expression through an index value (index)

  2. If we find that it is a number, we will put it on the stack directly

  3. If we find that the scanned symbol is a symbol, it can be divided into the following situations. If we find that the current symbol stack is empty, we can directly enter the stack. If there are operators in the symbol stack, we can compare them. If the priority of the current operator is less than or equal to that of the operators in the stack, we need to pop two numbers from the number stack and pop a symbol from the symbol stack for operation. The results will be put into the number stack, Then put the current operator into the symbol stack. If the priority of the current operator is greater than that of the operator in the stack, it will be directly put into the symbol stack.

  4. When the expression is scanned, the corresponding numbers and symbols are pop out of the number stack and symbol stack in sequence, and the operation is carried out.

  5. Finally, there is only one number in the number stack, which is the result of the expression.

Complete code implementation

/**
 * @author mengzhichao
 * @create 2022-04-16-11:12
 */
public class Calculator {
    public static void main(String[] args) {
        //Define an expression
        String expression = "7+2*6-4";
        //Create two stacks, a number stack and a symbol stack
        CalculatorArrayStack numStack = new CalculatorArrayStack(100);
        CalculatorArrayStack operStack = new CalculatorArrayStack(100);
        int index = 0; //For scanning
        int num1 = 0;
        int num2 = 0;
        int oper = 0;
        int res = 0;
        char ch =' '; //Save the char obtained from each scan in ch
        //Start scan expression of while loop
        while (true){
            //Get every character of experssion at one time
            ch = expression.substring(index,index+1).charAt(0);
            //Judge what ch is and deal with it accordingly
            if (operStack.isOper(ch)){ //If operator
                //Judge whether the current symbol stack is empty
                if (!operStack.isEmpty()){
                    //If the symbol stack has operators, compare them. If the priority of the current operator is less than or equal to that of the operators in the stack,
                    //You need to pop two numbers from the number stack and pop a symbol from the symbol stack,
                    //Carry out the operation, put the obtained result into the number stack, and then put the current operator into the symbol stack
                    if (operStack.priority(ch) <= operStack.priority(operStack.peek())){
                        num1 = numStack.pop();
                        num2 = numStack.pop();
                        oper = operStack.pop();
                        res = numStack.cal(num1,num2,oper);
                        //Put the result of the operation on the stack
                        numStack.push(res);
                        //Then put the current operator on the symbol stack
                        operStack.push(ch);
                    }else {
                        //If the priority of the current operator is higher than that of the operator in the stack, it will be directly put into the symbol stack
                        operStack.push(ch);
                    }
                }else {
                    //If it is empty, direct access symbol stack
                    operStack.push(ch); // 7 * 2
                }

            }else {
                numStack.push(ch - 48);
            }
            //Let index + 1 and judge whether to scan to the end of expression
            index++;
            if (index >= expression.length()){
                break;
            }
        }
        //When the expression is scanned, the corresponding numbers and symbols are pop out of the number stack and symbol stack in sequence, and the operation is carried out.
        while (true){
            //If the symbol stack is empty, the final result will be calculated, and there is only one number [result] in the number stack
            if (operStack.isEmpty()){
                break;
            }
            num1 = numStack.pop();
            num2 = numStack.pop();
            oper = operStack.pop();
            res = numStack.cal(num1,num2,oper);
            numStack.push(res);
        }
        //pop out the last number of the stack, which is the result
        int res2 = numStack.pop();
        System.out.printf("expression%s = %d",expression,res2);
    }
}


//Create a stack first
class CalculatorArrayStack{
    private int maxSize;  //Stack size
    private int[] stack;  //Array, array simulation stack, data is placed in the array
    private int top = -1; //Top indicates the top of the stack. Initialization to - 1 indicates no data

    //constructor 
    public CalculatorArrayStack(int maxSize){
        this.maxSize =maxSize;
        stack = new int[this.maxSize];
    }

    //Stack full
    public boolean isFull(){
        return top == maxSize - 1; //When the top of the stack is equal to the size of the stack, it indicates that the stack is full
    }

    //Stack empty
    public boolean isEmpty(){
        return top == -1;
    }

    //Stack push
    public void push(int value){
        //Determine whether the stack is full
        if (isFull()){
            System.out.println("Stack full");
            return;
        }
        top++;
        stack[top] = value;
    }

    //Returns the value at the top of the stack without any modification
    public int peek(){
        return stack[top];
    }


    //Out of stack - pop to return the data at the top of the stack
    public int pop(){
        //First judge whether the stack is empty
        if (isEmpty()){
            //Throw exception
            throw new RuntimeException("Stack empty,no data~");
        }
        int value = stack[top];
        top--;
        return value;
    }

    //Display the stack [convenience stack]. When traversing, you need to display data from the top of the stack
    public void list(){
        if (isEmpty()){
            System.out.println("Stack empty, no data~~");
            return;
        }

        for(int i = top; i >= 0; i--){
            System.out.printf("stack[%d]=%d\n",i,stack[i]);
        }
    }

    //Returns the priority of the operator. The priority is determined by the programmer. The priority is expressed in numbers
    //The higher 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 is only +, -, */
        }
    }

    //Judge whether 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 is used to store the calculation results
        switch (oper){
            case '+':
                res = num1 + num2;
                break;
            case '-':
                res = num2 - num1; //Pay attention to the order
                break;
            case '*':
                res = num1 * num2;
                break;
            case '/':
                res = num2 / num1;
                break;
            default:
                break;
        }
        return res; //Result return
    }
}

Run and test


After testing, we found that the results calculated by the program are consistent with those calculated by us, but we don't know if you have found a problem. When we change 7 in the expression to 70, our calculation results will have some problems.

How to solve this problem? Let's keep looking down!

Analysis of function optimization ideas and code improvement

  1. When processing a multi bit number, it can't be found that it is a number and immediately put it on the stack, because it may be a multi bit number

  2. When processing numbers, you need to look at one bit after the index of the expression. If it is a number, it will be scanned. If it is a symbol, it will be put on the stack

  3. Therefore, we need to define a variable string for splicing

/**
 * @author mengzhichao
 * @create 2022-04-16-11:12
 */
public class Calculator {
    public static void main(String[] args) {
        //Define an expression
        String expression = "7*2*2-5+1-5+3-4";
        //Create two stacks, a number stack and a symbol stack
        CalculatorArrayStack numStack = new CalculatorArrayStack(100);
        CalculatorArrayStack operStack = new CalculatorArrayStack(100);
        int index = 0; //For scanning
        int num1 = 0;
        int num2 = 0;
        int oper = 0;
        int res = 0;
        char ch =' '; //Save the char obtained from each scan in ch
        String keepNum = ""; //Multi bit number for splicing
        //Start scan expression of while loop
        while (true){
            //Get every character of experssion at one time
            ch = expression.substring(index,index+1).charAt(0);
            //Judge what ch is and deal with it accordingly
            if (operStack.isOper(ch)){ //If operator
                //Judge whether the current symbol stack is empty
                if (!operStack.isEmpty()){
                    //If the symbol stack has operators, compare them. If the priority of the current operator is less than or equal to that of the operators in the stack,
                    //You need to pop two numbers from the number stack and pop a symbol from the symbol stack,
                    //Carry out the operation, put the obtained result into the number stack, and then put the current operator into the symbol stack
                    if (operStack.priority(ch) <= operStack.priority(operStack.peek())){
                        num1 = numStack.pop();
                        num2 = numStack.pop();
                        oper = operStack.pop();
                        res = numStack.cal(num1,num2,oper);
                        //Put the result of the operation on the stack
                        numStack.push(res);
                        //Then put the current operator on the symbol stack
                        operStack.push(ch);
                    }else {
                        //If the priority of the current operator is higher than that of the operator in the stack, it will be directly put into the symbol stack
                        operStack.push(ch);
                    }
                }else {
                    //If it is empty, direct access symbol stack
                    operStack.push(ch); // 7 * 2
                }

            }else {
//                numStack.push(ch - 48);
                //Analysis ideas
                //1. When processing multi digit numbers, if it cannot be found that it is a number, it will be immediately put into the stack, because it may be multi digit numbers
                //2. When processing numbers, you need to look at one bit after the index of the expression. If it is a number, it will be scanned. If it is a symbol, it will be put on the stack
                //3. Therefore, we need to define a variable string for splicing

                //Number of processing bits
                keepNum += ch;

                //If ch is already the last bit of expression, it is directly put on the stack.
                if (index == expression.length() - 1){
                    numStack.push(Integer.parseInt(keepNum));
                }else {

                    //Judge whether the next character is a number. If it is a number, continue scanning. If it is an operator, put it on the stack
                    //Note that it's the last one, not the index++
                    if (operStack.isOper(expression.substring(index + 1, index + 2).charAt(0))) {
                        //If the last bit is an operator, put keepNum = "1" or "123" on the stack
                        numStack.push(Integer.parseInt(keepNum));
                        //important!!!!!!, keepNum empty
                        keepNum = "";
                    }
                }
            }
            //Let index + 1 and judge whether to scan to the end of expression
            index++;
            if (index >= expression.length()){
                break;
            }
        }
        //When the expression is scanned, the corresponding numbers and symbols are pop out of the number stack and symbol stack in sequence, and the operation is carried out.
        while (true){
            //If the symbol stack is empty, the final result will be calculated, and there is only one number [result] in the number stack
            if (operStack.isEmpty()){
                break;
            }
            num1 = numStack.pop();
            num2 = numStack.pop();
            oper = operStack.pop();
            res = numStack.cal(num1,num2,oper);
            numStack.push(res);
        }
        //pop out the last number of the stack, which is the result
        int res2 = numStack.pop();
        System.out.printf("expression%s = %d",expression,res2);
    }
}


//Create a stack first
class CalculatorArrayStack{
    private int maxSize;  //Stack size
    private int[] stack;  //Array, array simulation stack, data is placed in the array
    private int top = -1; //Top indicates the top of the stack. Initialization to - 1 indicates no data

    //constructor 
    public CalculatorArrayStack(int maxSize){
        this.maxSize =maxSize;
        stack = new int[this.maxSize];
    }

    //Stack full
    public boolean isFull(){
        return top == maxSize - 1; //When the top of the stack is equal to the size of the stack, it indicates that the stack is full
    }

    //Stack empty
    public boolean isEmpty(){
        return top == -1;
    }

    //Stack push
    public void push(int value){
        //Determine whether the stack is full
        if (isFull()){
            System.out.println("Stack full");
            return;
        }
        top++;
        stack[top] = value;
    }

    //Returns the value at the top of the stack without any modification
    public int peek(){
        return stack[top];
    }


    //Out of stack - pop to return the data at the top of the stack
    public int pop(){
        //First judge whether the stack is empty
        if (isEmpty()){
            //Throw exception
            throw new RuntimeException("Stack empty,no data~");
        }
        int value = stack[top];
        top--;
        return value;
    }

    //Display the stack [convenience stack]. When traversing, you need to display data from the top of the stack
    public void list(){
        if (isEmpty()){
            System.out.println("Stack empty, no data~~");
            return;
        }

        for(int i = top; i >= 0; i--){
            System.out.printf("stack[%d]=%d\n",i,stack[i]);
        }
    }

    //Returns the priority of the operator. The priority is determined by the programmer. The priority is expressed in numbers
    //The higher 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 is only +, -, */
        }
    }

    //Judge whether 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 is used to store the calculation results
        switch (oper){
            case '+':
                res = num1 + num2;
                break;
            case '-':
                res = num2 - num1; //Pay attention to the order
                break;
            case '*':
                res = num1 * num2;
                break;
            case '/':
                res = num2 / num1;
                break;
            default:
                break;
        }
        return res; //Result return
    }
}

Retest

The problem was successfully solved.

Tags: Java data structure Algorithm stack

Posted by jacko310592 on Mon, 18 Apr 2022 15:06:06 +0930