数据结构 - 栈、栈实现计算器

栈的概念

栈(stack)又名堆栈,它是一种运算受限的线性表。限定仅在表尾进行插入和删除操作的线性表。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素

  • 一种受限的线性表:仅能在表尾插入(入栈)、删除(出栈)
  • 表尾称为栈顶;另一端称为栈底
  • 栈:先进后出

在这里插入图片描述


Java基于数组实现栈

基于数组的栈有三个成员变量:

  • maxSize:表示栈大小(可以不用,内部设置)
  • int[] stack:数组
  • top:栈顶指针

实现栈需要有这些方法:

  • isFull():top == maxSize -1判断栈满
  • isEmpty():top == -1判断栈空
  • push(int value):入栈,往栈顶加入元素
  • pop():出栈,删除栈顶元素
  • show():遍历栈
  • peek():显示栈顶元素,不出栈
/**
 * 表示栈结构
 */
class ArrayStack{
    //栈的大小
    private int maxSize;
    //数组模拟栈
    private int[] stack;
    //top表示为栈顶,初始化为-1
    private int top = -1;

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

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

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

    /**
     * @param value 入栈值
     *
     * 入栈
     */
    public void push(int value){
        //判断是否栈满
        if (isFull()){
            System.out.println("=== 栈满 ===");
            return;
        }
        //指针后移
        top++;
        stack[top] = value;
    }

    /**
     * @return
     *
     * 出栈
     */
    public int pop(){
        //判断是否栈空
        if (isEmpty()){
            throw new RuntimeException("=== 栈空,没有数据 ===");
        }
        int value = stack[top];
        top--;
        return value;
    }

    /**
     * 遍历栈
     */
    public void show(){
        //判断是否栈空
        if (isEmpty()){
            System.out.println("=== 栈空,没有数据 ===");
            return;
        }
        //从栈顶开始显示数据
        for (int i = top;i >= 0;i--){
            System.out.println("stack["+i+"] = "+stack[i]);
        }
    }
    /**
     * @return
     * 返回当前栈顶的值,不出栈
     */
    public int peek(){
        return stack[top];
    }

}

测试类:

public class ArrayStackDemo {
    //测试
    public static void main(String[] args) {
        ArrayStack arrayStack = new ArrayStack(5);
        String key = "";
        boolean loop = true;
        Scanner scanner = new Scanner(System.in);

        while (loop){
            System.out.println("show:显示栈");
            System.out.println("exit:退出程序");
            System.out.println("push:入栈");
            System.out.println("pop:出栈");

            System.out.println("请输入选择:");
            key = scanner.next();

            switch (key){
                case "show":
                    arrayStack.show();
                    break;
                case "push":
                    System.out.println("请输入入栈的数据:");
                    int value = scanner.nextInt();
                    arrayStack.push(value);
                    break;
                case "pop":
                    try {
                        int popValue = arrayStack.pop();
                        System.out.println("出栈值:"+popValue);
                    }
                    catch (Exception e){
                        System.out.println(e.getMessage());
                    }
                    break;
                case "exit":
                    scanner.close();
                    loop = false;
                    break;
                default:
                    System.out.println("请输入正确的key");
                    break;
            }
        }
        System.out.println("=== 程序退出 ===");

    }

}

在这里插入图片描述


实现计算器

计算器都有paste功能

即粘贴一个字符串表达式:3+10*2-4/2-7

可以通过栈实现(仅实现了加减乘除,且没有错误表达式判断)

实现思路:

  1. 创建两个栈:数栈、符号栈;数栈存放表达式中的数字,符号栈存放运算符
  2. 设置一个扫描字符串索引index,一个字符一个字符的扫描表达式expression
  3. 当扫描为运算符时:
    3.1. 当符号栈为空,直接压入运算符
    3.2. 当符号栈不为空,判断栈中运算符与当前运算符优先级。当前运算符优先级小于或等于栈中运算符,拿出数栈的两个数字和栈中的栈顶运算符运算,然后将结果压入数栈,将当前运算符压入符号栈
  4. 当运算符扫描完,判断符号栈是否空,不为空(肯定只剩一个符号),弹出数栈两个数据符号栈运算符,计算得到结果压入数栈,该结果就是表达式运算结果

需要往栈结构ArrayStack里添加三个方法:判断字符是否为运算符、计算字符优先级、计算方法

 	/**
     * @param oper 传入的运算符
     * @return 返回优先级
     *
     * 返回运算符的优先级,优先级使用数字表示
     * 数字越大优先级越高
     */
    public int priority(int oper){
        //乘除运算符优先级为1
        if (oper == '*' || oper == '/'){
            return 1;
        }
        //加减运算符优先级为0
        else if (oper == '+' || oper == '-'){
            return 0;
        }
        //假定目前表达式只有 + - * /
        else {
            return -1;
        }
    }

    /**
     * @param val 运算符字符
     * @return
     * 判断是不是一个运算符
     */
    public boolean isOper(char val){
        return val == '+' || val == '-' || val == '*' || val == '/';
    }

    /**
     * @param num1 表达式后一个数
     * @param num2 表达式前一个数
     * @param oper 运算符
     * @return
     * 计算方式,得到运算结果
     */
    public int cal(int num1,int num2,int oper){
        int result = 0;
        switch (oper){
            case '+':
                result = num1 + num2;
                break;
            case '-':
                result = num2 - num1;
                break;
            case '*':
                result = num1 * num2;
                break;
            case '/':
                result = num2 / num1;
                break;
            default:
                break;
        }
        return result;
    }

计算器Calculator:根据前面的步骤完成

package com.company.stackCalculator;

import java.util.Scanner;

/**
 * @author zfk
 *
 * 栈实现计算器
 */
public class Calculator {

    public static void main(String[] args) {

        System.out.println("请输入表达式:");
        //表达式
        Scanner scanner = new Scanner(System.in);
        String expression = scanner.nextLine();
        //创建两个栈:数栈、符号栈
        ArrayStack numStack = new ArrayStack(5);
        ArrayStack operStack = new ArrayStack(5);
        //扫描表达式的索引
        int index = 0;
        //运算
        int num1 = 0;
        int num2 = 0;
        int oper = 0;
        int result = 0;
        //将每次扫描到的char保存到ch
        char ch = ' ';
        //多位数时,用于拼接
        String keepNum = "";
        //开始扫描expression
        while (true){
            //依次得到expression的每一个字符
            ch = expression.substring(index,index+1).charAt(0);
            //判断ch是否为运算符
            if (operStack.isOper(ch)){
                //判断当前符号栈是否为空
                if (!operStack.isEmpty()){
                    //不为空,处理:
                    //判断优先级,如果当前运算符的 优先级小于、等于 栈中的运算符,需要从数栈中pop出两个数
                    //再从符号栈中pop出运算符,运算得到结果,压入数栈,然后将当前运算符压入符号栈
                    if (operStack.priority(ch) <= operStack.priority(operStack.peek())){
                        num1 = numStack.pop();
                        num2 = numStack.pop();
                        oper = operStack.pop();
                        result = numStack.cal(num1,num2,oper);
                        //把结果压入数栈
                        numStack.push(result);
                        operStack.push(ch);
                    }
                    //当前运算符的 优先级大于 栈中的运算符,直接压入符号栈
                    else {
                        operStack.push(ch);
                    }
                }
                else {
                    //为空,直接入栈
                    operStack.push(ch);
                }
            }
            //如果是数字,直接放入数栈
            else {

                //注意:当多位数时需要连续入栈
                //numStack.push(ch - 48);

                //1.在处理数时,需要向expression表达式的index后再看一位
                //2.如果是数就继续扫描,如果是符号就入栈

                //keepNum字符变量用于拼接
                keepNum += ch;
                //如果ch已经是expression最后一位,就直接入栈
                if (index == expression.length()-1){
                    numStack.push(Integer.parseInt(keepNum));
                }
                else {
                    //如果后一位是运算符
                    if (operStack.isOper(expression.substring(index + 1, index + 2).charAt(0))) {
                        numStack.push(Integer.parseInt(keepNum));
                        //注意:要清空keepNum
                        keepNum = "";
                    }
                }
            }

            //index+1,判断是否扫描到expression最后
            index++;
            if (index >= expression.length()){
                break;
            }
        }

        //当扫描完毕,顺序弹出数栈、符号栈的数、符号,运算
        while (true){
            //当符号栈为空,计算到了最后的结果,数栈只有一个数字【结果】
            if (operStack.isEmpty()){
                break;
            }
            num1 = numStack.pop();
            num2 = numStack.pop();
            oper = operStack.pop();
            result = numStack.cal(num1,num2,oper);
            //把结果压入数栈
            numStack.push(result);
        }

        System.out.println("表达式:"+expression+" = "+numStack.pop());
    }


}

注意:输入为多位数字需要拼接为字符串(已实现)

结果:
在这里插入图片描述


总结

当前计算器完成的是中缀表达式的计算
中缀表达式是我们平时书写的表达式,但计算机并不好操作,通常会把中缀表达式转换为前缀表达式、后缀表达式

后续完成前缀表达式、后缀表达式

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值