03栈 stack

栈 stack

  • 一个先入后出的有序列表。

在这里插入图片描述

数组实现栈:

package msp.cai.stack;

/*
 * 数组实现栈
 */
public class ArrayStackDemo {
    public static void main(String[] args) {
        ArrayStack stack = new ArrayStack(5);
        System.out.println("== 入栈 ==");
        stack.push(1);
        stack.push(2);
        stack.push(3);
        stack.push(4);
        stack.push(5);
        stack.showStack();
        System.out.println("== 出栈 ==");
        System.out.println(stack.pop());
        System.out.println(stack.pop());
        System.out.println(stack.pop());
        System.out.println(stack.pop());
        System.out.println(stack.pop());
    }
}

class ArrayStack {
    int maxSize;    // 最大长度
    int top = -1;    // 栈顶
    int[] arr;  // 存放数据

    public ArrayStack(int maxSize) {
        this.maxSize = maxSize;
        arr = new int[this.maxSize];
    }

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

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

    // 入栈
    public void push(int data) {
        if (isFull())
            return;
        arr[++top] = data;
    }

    // 出栈
    public int pop() {
        if (isEmpty())
            return -1;
        return arr[top--];
    }

    // 打印栈
    public void showStack() {
        if (isEmpty()) {
            System.out.println("栈为空~");
        } else {
            System.out.println("栈中数据为:");
            for (int i = 0; i <= top; i++) {
                System.out.printf("%d\t",arr[i]);
            }
            System.out.println();
        }
    }
}

栈实现计算器:

思路:

  • 使用两个栈,munStack(数字栈) operaStack(符号栈)
  1. 通过一个index(索引),遍历表达式字符串
  2. 如果是数字,直接入栈
  3. 如果是字符:
    1. 若栈为空,直接push
    2. 若栈不为空:
      1. 若当前符号优先级大于栈顶符号的优先级,push
      2. 否则,从数字栈pop两个数,从符号栈pop运算符,将运算结果push到数字栈,最后将当前符号push到符号栈。
    3. 当表达式扫描完毕,顺序计算。即pop两个数与一个运算符,将计算结果push到数字栈。
package msp.cai.stack;

/*
 * 栈实现表达式计算
 */
public class ArrayStackDemo01 {
    public static void main(String[] args) {
        // 创建数字栈与符号栈
        numStack n_stack = new numStack(100);
        operaStack o_stack = new operaStack(50);

        String exp = "1+1*8+2*6";
        for (int i = 0; i < exp.length(); i++) {
            char item = exp.charAt(i);
            // 符号
            if (item=='+' || item=='-' || item=='*' || item=='/') {
                if (o_stack.isEmpty())
                    o_stack.push(item);
                else {
                    char top_opera = o_stack.getTop();
                    if ((item=='*' || item=='/') && (top_opera=='+' || top_opera=='-'))
                        o_stack.push(item);
                    else {
                        int num1 = n_stack.pop();
                        int num2 = n_stack.pop();
                        char ope = o_stack.pop();
                        n_stack.push(calculation(num1,num2,ope));
                        o_stack.push(item);
                    }
                }
            }
            // 是数字,直接入栈
            else {
                int num = item - '0';
                n_stack.push(num);
            }
        }
        while (!o_stack.isEmpty()) {
            int num1 = n_stack.pop();
            int num2 = n_stack.pop();
            char ope = o_stack.pop();
            n_stack.push(calculation(num1,num2,ope));
        }
        System.out.println("计算结果为: " + n_stack.pop());
    }

    // 计算方法
    public static int calculation(int nim1, int num2, char ope) {
        int result = 0;
        switch (ope){
            case '+':
                result = num2 + nim1;
                break;
            case '-':
                result = num2 - nim1;
                break;
            case '*':
                result = num2 * nim1;
                break;
            case '/':
                result = num2 / nim1;
                break;
        }
        return result;
    }
}

// 数字栈
class numStack {
    private int maxSize;
    private int top;
    private int[] arr;

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

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

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

    // 入栈
    public void push(int data) {
        if (isFull())
            return;
        arr[++top] = data;
    }

    // 出栈
    public int pop() {
        if (isEmpty())
            return -1;
        return arr[top--];
    }
}
// 符号栈
class operaStack {
    private int maxSize;
    private int top;
    private char[] arr;

    public operaStack(int maxSize) {
        this.maxSize = maxSize;
        top = -1;
        arr = new char[this.maxSize];
    }

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

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

    // 入栈
    public void push(char data) {
        if (isFull())
            return;
        arr[++top] = data;
    }

    // 出栈
    public char pop() {
        if (isEmpty())
            return '0';
        return arr[top--];
    }

    // 获取栈顶元素
    public char getTop() {
        if (isEmpty()) {
            return '0';
        }
        return arr[top];
    }
}

前缀 中缀 后缀 表达式:

  • 前缀

    • 从右至左扫描表达式,遇到数字入栈,遇到运算符时,弹出两个数字进行计算,将结果入栈。
    • 中缀:(3+4)*5 -6 --> 前缀:- * + 3 4 5 6
  • 中缀

    • 我们熟知的,但对于计算机来说不好操作。
  • 后缀表达式

    • 逆波兰表达式,与前缀相似,运算符位于数字后面。
    • 从左至右扫描表达式,遇到数字入栈,遇到运算符时,弹出两个数字进行计算,将结果入栈。
    • 中缀:(3+4) * 5 - 6 --> 后缀:3 4 + 5 * 6 -

中缀转后缀:

中缀:1 + ((2+3) * 4) - 5

  1. 初始化两个栈:符号栈s1中间结果栈s2
  2. 从左至右扫描中缀表达式;
  3. 遇到操作数,push到s2;
  4. 遇到运算符时,
    1. 若s1为空,或者栈顶为“(”时,直接将此运算符push到s1;
    2. 否则若优先级高于栈顶运算符,直接将此运算符push到s1;
    3. 否则,将s1栈顶运算符pop,然后push到s2,返回4.1,重新判断。
  5. 遇到括号时,
    1. 左括号“(”,直接push到s1;
    2. 右括号“)”,依次pop s1中的符号,push到s2中,直到遇到左括号,此时就相当于去掉了一对括号。
  6. 重复步骤2-5,直至扫描完中最表达式;
  7. 将s1中剩余运算符依次pop并push到s2
  8. s2出栈结果的逆序即为后缀表达式。
package msp.cai.stack;

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

/*
 *  使用栈实现计算表达式:
 *    1. 获取表达式字符串
 *    2. 中缀 -->  后缀
 *    3. 计算结果
 */
public class BolanCalculator {
    public static void main(String[] args) {
        // 中缀表达式
        String midStr = "1 + ( ( 2 + 3 ) * 4 ) - 5";
        System.out.println("中缀表达式为: " + midStr);
        // 将中缀转后缀 "1 2 3 + 4 * + 5 - "
        String rearStr = mid2rear(midStr);
        System.out.println("后缀表达式为: " + rearStr);
        String[] rearStrArr = rearStr.split(" ");
        // 入栈
        Stack<String> stack = new Stack<String>();
        for (String s : rearStrArr) {
            if (!isNotANumber(s))
                stack.push(s);
            else {
                int num1 = Integer.parseInt(stack.pop());
                int num2 = Integer.parseInt(stack.pop());
                switch (s) {
                    case "+":
                        stack.push(String.valueOf(num2+num1));
                        break;
                    case "-":
                        stack.push(String.valueOf(num2-num1));
                        break;
                    case "*":
                        stack.push(String.valueOf(num2*num1));
                        break;
                    case "/":
                        stack.push(String.valueOf(num2/num1));
                        break;
                }
            }
        }
        System.out.println("计算结果为: " + stack.pop());
    }

    // 中缀表达式转后缀表达式
    public static String mid2rear(String midStr) {
        // 1. 初始化两个栈
        Stack<String> s1 = new Stack<String>();     // 符号栈
        Stack<String> s2 = new Stack<String>();     // 中间结果栈
        String[] str = midStr.split(" ");
        // 2. 从左至右依次扫描
        for (String s : str) {
            // 3. 遇到操作数,push
            if (!isNotANumber(s))
                s2.push(s);
            // 4. 遇到运算符时
            else if (!isBracket(s)){
                while (true) {
                    // 4.1 若s1为空,或栈顶为“(”时,直接入栈
                    if (s1.isEmpty() || s1.peek().equals("(")) {
                        s1.push(s);
                        break;
                    }
                    // 4.2 当前字符优先级高于栈顶字符,直接入栈
                    if (getPriority(s) > getPriority(s1.peek())) {
                        s1.push(s);
                        break;
                    }
                    // 4.3 否则将s1栈顶运算符pop,push到s2,返回4.1
                    String pop = s1.pop();
                    s2.push(pop);
                }
            }
            // 5. 遇到括号时
            else {
                // 5.1 遇到“(”,直接push
                if (s.equals("("))
                    s1.push(s);
                // 5.2 依次pop s1中的符号,push到s2中,直到遇到左括号
                else {
                    String pop;
                    while (!(pop=s1.pop()).equals("("))
                        s2.push(pop);
                }
            }
        }
        // 6. 将s1中剩余运算符依次pop并push到s2
        while (!s1.isEmpty())
            s2.push(s1.pop());
        // 7. 后缀表达式即为s2出栈的逆序
        ArrayList<String> rearArr = new ArrayList<String>();
        while (!s2.isEmpty()) {
            rearArr.add(s2.pop());
        }
        StringBuilder rearStr = new StringBuilder();
        for (int i = rearArr.size()-1; i >= 0; i--) {
            rearStr.append(rearArr.get(i)).append(" ");
        }
        return rearStr.toString();
    }

    // 判断字符串是否为操作数
    public static boolean isNotANumber(String str) {
        return str.equals("+") || str.equals("-") || str.equals("*")
                || str.equals("/") || str.equals("(") || str.equals(")");
    }

    // 判断字符串是否是括号
    public static boolean isBracket(String str) {
        return str.equals("(") || str.equals(")");
    }

    // 获取字符的优先级
    public static int getPriority(String str) {
        if (str.equals("*") || str.equals("/"))
            return 1;
        else if (str.equals("+") || str.equals("-"))
            return 0;
        else
            return -1;
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值