How to write a string calculator elegantly (JAVA)

String calculator

Coordinates 2020-4-24
pass-Huawei two sides. The
interviewer gave a dynamic picture and asked me: Can you write a simple string calculator in twenty minutes?
Think slightly: it should be okay.
Then in the confusion of thinking, I want to use recursion, but also want to use the stack. Finally, I wrote a calculator with countless null pointer abnormalities. After the end, I learned from it, and today I will teach you to write a string calculator.

First, we must need a function to determine whether a character is a number,

 public static boolean isNum(char x){
    
    
        return x>=48 && x<=57;
    }//利用ascall码判断是否为数字

With it, we proceed to the second step, designing algorithm ideas.
As for the problem-solving idea of ​​the string calculator, I only saw one on the Internet, which is to use the infix Polish expression to convert to a suffix, and then calculate one by one. In the process of my interview, my first reaction was to use recursion to reduce all parentheses, and then calculate in the order of multiplication and division followed by addition and subtraction. Today we will improve both ideas.

Idea 1: Polish expression
First, we look at the following expression 2+3*(6-2). This expression, which is the expression we input, is the infix Polish expression. We convert it into a postfix expression to get Should be 2 3 6 2-* +
What rule did you find? That is to put the operator after the number in the order of operation. When we calculate, we only need a stack to assist, and we can calculate the result in order. Up.
Some friends said, I understand the idea, how to write it? Let me speak slowly.

The first step, we need some auxiliary tools,
1. String

StringBuilder stringBuilder = new StringBuilder();

Use StringBuilder to store the converted suffix expression.

2. Stack

Stack<Character> stack = new Stack<>();

We use the stack to assist storage.

3. The character form of the original expression

char x[] = str.toCharArray();

We convert the string passed into the function into a character array, so that it is convenient to use the isNum function to judge

So now the function looks like this

 public static String inorder (String str){
    
    
        Stack<Character> stack = new Stack<>();
        char x[] = str.toCharArray();
        StringBuilder stringBuilder = new StringBuilder();
        retrun null;
        }

Next, we traverse the entire character array

 public static String inorder (String str){
    
    
        Stack<Character> stack = new Stack<>();
        char x[] = str.toCharArray();
        StringBuilder stringBuilder = new StringBuilder();
        for(int i=0;i<x.length;i++){
    
    

        }
        retrun null;
        }

Now think about it, what should we do when we traverse the array?
There are several situations:
1. The current character is a number
2. The current character is an operator
3. The current character is a bracket

In case 1, we only need to add it to the result, because in our final suffix expression, the numbers are arranged in the original order.

 public static String inorder (String str){
    
    
        Stack<Character> stack = new Stack<>();
        char x[] = str.toCharArray();
        StringBuilder stringBuilder = new StringBuilder();
        for(int i=0;i<x.length;i++){
    
    
            if (isNum(x[i])) {
    
     //该字符为数字,直接加入结果
                stringBuilder.append(x[i]);
                continue;
            }
        }
        retrun null;
        }

Some students said: What if there are multiple digits? We make some improvements

 public static String inorder (String str){
    
    
        Stack<Character> stack = new Stack<>();
        char x[] = str.toCharArray();
        StringBuilder stringBuilder = new StringBuilder();
        for(int i=0;i<x.length;i++){
    
    
            if (isNum(x[i])) {
    
     //该字符为数字,直接加入结果
                stringBuilder.append(x[i]);
                if ((i<x.length-1&&!isNum(x[i+1]))||i==x.length-1)){
    
    
                    stringBuilder.append(" ");
                }
                continue;
            }
        }
        retrun null;
        }

In this step, we add the number to the result and make a judgment. If the current character is already the last character, we add a space after it, or, the next character of the current character is not a number, then we also add it Add a space after it.

In cases 2 and 3
, the priority of the / symbol is higher than ± during the operation , so we process / first , and when we encounter */, we put it in the auxiliary stack

 if (x[i]=='*'||x[i]=='/'){
    
    
                stack.push(x[i]);
                continue;
            }

Parentheses have higher priority than multiplication and division. What should I do?
Considering the characteristics of the stack, we need to enter the stack when we encounter the left parenthesis, and for the time being think that they are at the same level as multiplication and division, as follows

 if (x[i]=='*'||x[i]=='/'||x[i]=='('){
    
    
                stack.push(x[i]);
                continue;
            }

After encountering the left parenthesis, we still perform the original logical operations until we find a right parenthesis, which is the parenthesis matching rule. At
this time, we need to operate on the stack and loop out the stack until we find the corresponding right parenthesis. Opening parenthesis, we have completed a conversion inside the parenthesis,

if (x[i]==')'){
    
    
                while (!stack.isEmpty()){
    
    
                    if (stack.peek()=='('){
    
    
                        stack.pop();
                        continue;
                    }
                    stringBuilder.append(stack.pop());
                }
                continue;
            }

Some students may not think it is very vivid, let us simulate the contents of the stack,
(3+4) before the closing parenthesis,
the contents of the stack is (+
and the string content is 3 4
then after we pop the stack, the contents of the string The content becomes 3 4 +
and there is no operator in the brackets in the stack.
At this time, we have completed a suffix conversion in the brackets.

At this time, the bar is fine (crossed out)-the students said again, what about addition and subtraction?
When encountering addition and subtraction, we have to consider several situations
1. The current stack is empty, and the symbol is directly put on the stack
2. The current stack is not empty, and the top element of the stack is (, indicating that ± is the operator in the brackets, we Also directly into the stack,
3. The current stack is not empty, the top element of the stack is not (, indicating that ± may be in parentheses, but the current order of operation ± should be arranged behind the top element of the stack, after we pop the stack, then ± put in the stack

if (x[i]=='+'||x[i]=='-'){
    
    
               while (!stack.isEmpty()&&stack.peek()!='('){
    
    
                   stringBuilder.append(stack.pop());
               }
               stack.push(x[i]);
               continue;
            }

Finally, we add the return statement to get the postfix expression

return stringBuilder.toString();

The complete function is as follows

public static String inorder (String str){
    
    
        Stack<Character> stack = new Stack<>();
        char x[] = str.toCharArray();
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0;i<x.length;i++){
    
    
            if (isNum(x[i])) {
    
    
                stringBuilder.append(x[i]);
                if (((i<x.length-1&&!isNum(x[i+1]))||i==x.length-1)){
    
    
                    stringBuilder.append(" ");
                }
                continue;
            }
            if (x[i]=='*'||x[i]=='('||x[i]=='/'){
    
    
                stack.push(x[i]);
                continue;
            }
            if (x[i]==')'){
    
    
                while (!stack.isEmpty()){
    
    
                    if (stack.peek()=='('){
    
    
                        stack.pop();
                        continue;
                    }
                    stringBuilder.append(stack.pop());
                }
                continue;
            }
            if (x[i]=='+'||x[i]=='-'){
    
    
               while (!stack.isEmpty()&&stack.peek()!='('){
    
    
                   stringBuilder.append(stack.pop());
               }
               stack.push(x[i]);
               continue;
            }

        }
        return stringBuilder.toString();
    }

The next step is to calculate the result of the suffix expression. This step is very simple. We will not explain it. We only need to push the number into the stack, pop the stack when encountering the operator, and push the stack again after obtaining the calculation result.
Note/and-You need to reverse the order of the two numbers popped from the stack to calculate the correct result

public static Integer help(String str){
    
    
        Stack<Integer> num = new Stack<>();
        StringBuilder stringBuilder = new StringBuilder();
        char x[] = str.toCharArray();
        for (int i =0;i<x.length;i++){
    
    
            if (isNum(x[i])){
    
    
                stringBuilder.append(x[i]);
                if (i+1==x.length){
    
    
                    num.push(Integer.parseInt(stringBuilder.toString()));
                }
                if (x[i+1]==' '){
    
    
                    num.push(Integer.parseInt(stringBuilder.toString()));
                    stringBuilder.delete(0,stringBuilder.length());
                    continue;
                }
            }
            if (x[i]=='+'){
    
    
                num.push(num.pop()+num.pop());
            }
            if (x[i]=='-'){
    
    
                int a = num.pop();
                int b = num.pop();
                num.push(b-a);
            }
            if (x[i]=='*'){
    
    
                num.push(num.pop()*num.pop());
            }
            if (x[i]=='/'){
    
    
                int a = num.pop();
                int b = num.pop();
                num.push(b/a);
            }
        }
        return num.pop();
    }

In this way, we call two functions in the main function to get the final calculation result.

See the second article for recursion.

Guess you like

Origin blog.csdn.net/qq_45789385/article/details/105733553