用数组模拟栈实现计算器

一、初始版本:

只能对0-9的数进行四则运算

第一次结果出错,因为在循环把表达式分割入栈时“新符号的优先级小于等于符号栈已有符号的优先级”这一步,在进行计算后只把计算结果加入数栈中,忘了把表达式中的下一个运算符加入到符号栈。

//用栈实现计算器
/**
 * 思路:需要两个栈,一个数字栈,一个符号栈,分别存放数字和运算符, 通过一个游标遍历表达式,依次把数字和符号存入栈中,
 * 其中,符号栈:如果栈为空,直接存入;如果栈中有了符号,需要先比较二者优先级;
 * 如果新符号的优先级小于等于已有的,从数栈取出2个数,从符号栈取出一个符号,进行运算,运算结果存入数栈中; 如果新的优先级大于已有的,直接存入,
 * 直到表达式遍历完成,把数和符号从栈中取出,进行运算,要注意减法和除法时的情况 难点:一个是怎么判断运算符的优先级;判断是数字还是运算符
 */
public class StackCounter {

    public static void main(String[] args) {
        String expresion = "3+3*6-2";
        int flag = 0;// 游标
        int num1 = 0;
        int num2 = 0;
        int oper = 0;
        int res=0;
        char ch = 0;
        ArrStack2 numStack = new ArrStack2(10);
        ArrStack2 operStack = new ArrStack2(10);

        // 通过循环判断进行入栈
        while (true) {
            // 应该先用循环把表达式分割开
            ch = expresion.substring(flag, flag + 1).charAt(0);// substring()是分割String字符串得到子字符串,参数int是分割的起点,charAt()是返回指定位置的字符
            if (operStack.isOper(ch)) {// 是运算符
                if (!operStack.isEmpty()) {
                    // 符号栈不是空,要先进行优先级判断再往里面存入
                    if (operStack.periority(ch) <= operStack.periority(operStack.peek())) {// 如果新符号的优先级小于等于已有的,从数栈取出2个数,从符号栈取出一个符号,进行运算,运算结果存入数栈中;
                        num1 = numStack.pop();
                        num2 = numStack.pop();
                        oper = operStack.pop();
                        res = numStack.cal(num1, num2, oper);
                        numStack.push(res);
                        operStack.push(ch);
                    } else {// 如果新的优先级大于已有的,直接存入
                        operStack.push(ch);
                    }
                } else {
                    // 符号栈为空,直接存入
                    operStack.push(ch);
                }
            } else {// 是数字
                numStack.push(ch - 48);// ch是字符,不是Int,需要先转换类型
            }
            flag++;
            if (flag >= expresion.length()) {
                break;
            }
        }
        
        //进行计算,需要出栈
        while(true) {
            //如果符号栈为空,说明数栈里的数据就是最后的解
            if(operStack.isEmpty()) {
                break;
            }
            num1=numStack.pop();
            num2=numStack.pop();
            oper=operStack.pop();
            res=numStack.cal(num1,num2,oper);
            numStack.push(res);
        }
        
        System.out.println("表达式的解为:"+numStack.peek());
    }
}

class ArrStack2 {
    /**
     * 用数组模拟栈,需要几个功能,入栈、出栈、栈满、栈空、显示 新增功能:判断是数字还是运算符;设置运算符的优先级;规定计算规则
     */

    public int top = -1;// 栈顶
    public int maxSize;
    public int stack[];

    // 构造器:初始化对象
    public ArrStack2(int maxSize) {
        this.maxSize = maxSize;
        stack = new int[maxSize];
    }

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

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

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

    // 出栈
    public int pop() {
        if (isEmpty()) {
            System.out.println("栈空,无法取出数据");
            return -1;
        }
        int value;
        value = stack[top];
        top--;
        return value;
    }

    // 显示
    public void list() {
        if (isEmpty()) {
            System.out.println("栈空");
            return;
        }
        while (top != -1) {
            System.out.println("stack[" + top + "]" + "=" + stack[top]);
            top--;
        }
    }

    // 设置优先级,用数字表示,数字越大,优先级越高
    public int periority(int oper) {
        if (oper == '*' || oper == '/') {
            return 1;
        } else if (oper == '+' || oper == '-') {
            return 0;
        } else {
            return -1;
        }
    }

    // 判断是数字还是运算符
    public boolean isOper(char ch) {
        return ch == '*' || ch == '/' || ch == '+' || ch == '-';
    }

    public int cal(int num1, int num2, int oper) {
        int res = 0;// 计算结果
        switch (oper) {
        case '+':
            res = num1 + num2;
            break;
        case '-':
            res = num2 - num1;
            break;
        case '*':
            res = num1 * num2;
            break;
        case '/':
            res = num2 / num1;
            break;
        default:
            break;
        }
        return res;
    }

    public int peek() {// 返回栈顶的值,但是并非是让出栈
        return stack[top];
    }

}

运行之后,结果正确

但是,还不能对多位数和括号进行操作,下一步进行这些操作

此外,发现当表达式中加减顺序为先减后加时,计算会出错

二、能够对多位数进行计算:定义一个字符串keepnum,然后将一中判断是数字后的入栈操作更改为:

如果一个数字后还是数字,就拼接在一起,并且通过外部的while大循环能够重复这一步骤直到最后一位。

keepnum += ch;
if (flag == expresion.length() - 1) {
    numStack.push(Integer.parseInt(keepnum));
} else {
    if (numStack.isOper(expresion.substring(flag + 1, flag + 2).charAt(0))){
        // 是符号,那就把keepnum入栈
        numStack.push(Integer.parseInt(keepnum));
        keepnum = "";// keepnum必须置空消除累加
    }
}

               

要注意的是:1.当一个多位数找完拼接后,要把keepnum置空,否则会保留上次的数据;

                      2.在判断下一位是不是数字之前,要先判断这个数字是不是最后一位,否则会有数组越界的错误

关于加减顺序不同导致的计算错误:通过把“+”优先级调低于“-”得到了实现,但是还有别的方法吗?

// 设置优先级,用数字表示,数字越大,优先级越高
    public int periority(int oper) {
        /*
        if (oper == '*' || oper == '/') {
            return 1;
        } else if (oper == '+' || oper == '-') {
        return 0;
        } else {
            return -1;
        }
        */
        if (oper == '*' || oper == '/') {
            return 2;
        } else if (oper == '-') {
            return 1;
        } else if (oper == '+') {
            return 0;
        } else {
            return -1;
        }
    }

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值