栈的应用

栈的应用

1.使用栈计算一个表达式的结果,如:7x2x5-3-6+5+9 (中缀表达式)

思路:创建两个栈,一个存储数据,一个存储用算符;

① 定义一个index索引,遍历表达式

② 如果为数字进入数据栈;

③ 若为符号,判断如果当前符号栈为null则直接压入,若不为null,则比较优先级大小,如果当前符号小于等于栈中符号优先级,就需要从数据栈栈中弹出两个数,从符号栈中弹出一个符号,进行与运算,将得到的结果入数据栈,然后将当前运算符入符号栈;如果当前符号大于栈中符号优先级,直接入符号栈;

④ 当表达式扫描完,就顺序从数栈和符号栈中pop出相应的数和符号,并运算;

⑤ 最后数栈中只有一个数,为结果;

package com.sratct.stack;

public class StackList {
    public static void main(String[] args) {
        StackArray numStack = new StackArray(10); // 数栈
        StackArray operStack = new StackArray(10); // 符号栈
        String expression = "30+2*6-2";
        char[] chars = expression.toCharArray();
        int num1 = 0;  // 弹出第一个数
        int num2 = 0; // 弹出第二个数
        int val = 0; // 运算的结果
        int oper = 0; //接收运算符
        String keepNumber = ""; //用于拼接多位数
        int i=0;
        for (char ch : chars) {
            // 判断当前的元素是不是运算符
            if (operStack.isOper(ch)) {
                // 是运算符,判断符号栈中是否有元素
                if (!operStack.isEmpty()) {
                    // 不为空,判断当前运算符和符号栈中的运算符优先级,
                    if (operStack.priority(ch) <= operStack.priority(operStack.peek())) {
                        //小于等于, 从符号栈中pop出一个元素,从数栈中pop出两个元素,运算后结果入数栈
                        num1 = numStack.pop();
                        num2 = numStack.pop();
                        oper = operStack.pop();
                        val = operStack.cal(num1, num2, oper);
                        numStack.push(val);
                        operStack.push(ch);
                    } else {
                        //大于,直接插入
                        operStack.push(ch);
                    }

                } else{
                    // 为空,直接插入
                    operStack.push(ch);
                }
            } else {
                // 是数字时,不能立即入数栈,由于数字为字符会将多位数分成几个字符;如:13 ==> '1' 和 '3'
                // 在处理多为数时,需要当前元素后再看一位,如果为符号则入数栈,不是则继续往后走;
                // 每次将字符拼接到keepNumber中进行保存
                keepNumber += ch;
               //  如果ch是最后一位,则直接入入栈
                if (i == expression.length()-1) {
                    numStack.push(Integer.parseInt(keepNumber));
                } else {
                    // 判断下一位ch是不是数字,若为数字,继续看下一位,若为运算符,则入数栈
                    if (operStack.isOper(chars[i+1])) {
                        numStack.push(Integer.parseInt(keepNumber));
                        // 清空keepNumber
                        keepNumber = "";
                    }
                }
            }
            i++;
        }

        // 当运算表达式循环完毕,就继续从符号栈中弹出一个,从数栈中弹出两个进行运算,直到符号栈中为空,最终数栈中剩下的为最终结果
       while (true) {
           if (operStack.isEmpty()) {
               break;
           }
           num1 = numStack.pop();
           num2 = numStack.pop();
           oper = operStack.pop();
           val = operStack.cal(num1,num2,oper);
           numStack.push(val);
       }
        System.out.println(numStack.pop());
    }
}

class StackArray {
    private int maxSize;
    private int top;
    private int[] arrayStack;

    public StackArray(int maxSize) {
        this.maxSize = maxSize;
        arrayStack = new int[maxSize];
        top = -1;
    }

    // 判断栈是否为空
    public boolean isEmpty() {
        return top == -1;
    }

    // 判断栈是否满
    public boolean isFull() {
        return top == maxSize-1;
    }

    // 查看栈首元素
    public int peek() {
      return arrayStack[top];
    }

    // 入栈
    public void push(int data) {
        if (isFull()) {
            System.out.println("栈已满");
            return;
        }
        top++;
        arrayStack[top] = data;

    }
    // 出栈
    public int pop() {
        if (isEmpty()) {
           throw new RuntimeException("栈为null");
        }
        int temp = arrayStack[top];
        top--;
        return temp;
    }
    //遍历栈
    public void getList() {
        if (isEmpty()) {
            System.out.println("栈为null");
            return;
        }
        for (int i=top; i>=0; i--) {
            System.out.println(arrayStack[i]);
        }
    }

    // 返回运算符的优先级,自己定义,目前只有+、-、*、/
    public int priority(int oper){
       if (oper == '*' || oper == '/') {
           return 1;
       } else if (oper == '+' || oper == '-') {
           return 0;
       } else {
           return -1;
       }
    }

    // 判断该元素是不是运算符
    public boolean isOper(char val) {
        return val=='*' || val == '/' || val == '+' || val == '-';
    }

    // 两个数进行运算
    public int cal(int num1,int num2,int oper) {
        int val = 0;
        switch (oper) {
            case '-':
                val = num2-num1;  // 注意,后弹出的数减去前一个数
                break;
            case '+':
                val = num1 + num2;
                break;
            case '*':
                val =num1 * num2;
                break;
            case '/':
                val = num2 / num1;
                break;
            default:
                break;
        }
        return val;
    }
}

2.前缀(波兰表达式)、中缀、后缀表达式(逆波兰表达式)

1) 前缀表达式的计算机求值

从右至左扫描的表达式,遇到数字时,将数字压入堆栈,遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算,并将结果入栈,重复上述操作直到表达式的最左端,最后运算得到的值即为表达式的结果;

例如: (3+4)x 5 - 6对应的前缀表达式为: - x + 3 4 5 6 ,求值如下步骤:

① 从右至左扫描,将6、5、4、3压入堆栈;

② 遇到+号时,弹出3和4,计算3+4的值为7,再将7压入栈;

③ 接下来是 x 运算符,因此弹出7和5,计算7 x 5 =35,将35入栈;

④ 最后是 - 运算符,计算出35 - 6的值,即29,由此得到最终结果;

2) 中缀表达式

中缀表达式就是我们常见的表达式: (3+4)x 5 - 6

此表达式对我们人来说是非常容易计算,但是计算机就不好操作,计算机在计算结果时一般采用后缀表达式;

3)后缀表达式

① 后缀表达式又称逆波兰表达式

② 举例:(3+4)x 5 - 6对应的后缀表达式为3 4 + 5 x 6 -

③后缀表达式的计算机求值

从左至右扫描表达式,遇到数字,将数字压入栈中,遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算,并将结果入栈,重复上述操作直到表达式的最左端,最后运算得到的值即为表达式的结果;

例如: (3+4)x 5 - 6对应的前缀表达式为:3 4 + 5 x 6 - ,求值如下步骤:

① 从左至右扫描,将3、4压入堆栈;

② 遇到+号时,弹出3和4,计算3+4的值为7,再将7压入栈;

③ 将5入栈

④ 接下来是 x 运算符,因此弹出5和7,计算7 x 5 =35,将35入栈;

⑤ 将6入栈

④ 最后是 - 运算符,计算出35 - 6的值,即29,由此得到最终结果;

posted @ 2021-04-15 15:45  撑起一片阳光  阅读(433)  评论(0编辑  收藏  举报