数据结构入门教程-栈的应用实例1

2020-02-01  本文已影响0人  会上树的程序猿

在这篇文章中数据结构入门教程-栈,我们了解了栈的基本操作,如入栈(push)和出栈(pop)这两个重要的特性,本篇我们来说说栈的应用实例

需求

当然我们可以直接利用计算机来得出该表达式的结果,这里只是简单的表达式,说白了,我们来实现计算器的简单计算功能,因为我们的表达式中既有数字也有运算符,因此示意图如下:

微信截图_20200201120143.png

这是我的图,我需要两个栈分别用来保存数字和操作符,下面简单的分析下思路

接着我们来看代码实现

代码实现
 //定义栈结构类
class ArrayStack {
private int maxSize; //表示栈的最大容量
private int[] stack; //stack实际用来保存数据的
private int top = -1; //top表示栈顶,初始值为-1,表示此时栈中是没有数据的

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

//栈满的条件
public boolean isFull(){
    return top == maxSize -1;
}
//栈空的条件
public boolean isEmpty(){
    return top == -1;
}
//返回栈顶的值,但不自增
public int peek(){
    return stack[top];
}
//入栈操作
public void push(int element){
    if (isFull()){
        throw new ArrayIndexOutOfBoundsException("栈已经满了~");
    }
    top ++;
    stack[top] = element;
}
//出栈操作
public int pop(){
    if (isEmpty()){
        throw new RuntimeException("栈空~");
    }
    int element = stack[top];
    top --;
    return element;
}
//打印操作
public void print(){
    if (isEmpty()){
        System.out.println("栈空~");
        return;
    }
    for (int i = top; i >= 0 ; i--) {

        System.out.printf("stack[%d]=%d\n",i,stack[i]);
    }

}


//返回操作符的优先级,这里规定乘除的优先级为1,加减为0

/**
 *
 * @param optional 传入的操作符
 * @return
 */
public int priority(int optional){
    if (optional == '*' || optional == '/'){
        return 1;
    }
    if (optional == '+' || optional == '-'){
        return 0;
    }else {
        return -1; //这里的操作符默认W为+ - * /这四种.
    }
}
//判断是否是一个操作符
public boolean isOper(char value){
    return value == '+'|| value == '-' || value == '*'|| value == '/';
}
//计算方法

/**
 *
 * @param num1 数字num1
 * @param num2 数字num2
 * @param oper 操作符包括(+ - * /)
 * @return
 */
public int cal(int num1,int num2,int oper){
    //定义一个临时的变量用来存放计算的结果值,默认为0
    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;
  }
}

上述是我们栈的定义,其中里面的方法最重要的是计算方法和操作符的判断的方法,代码简单这里不多说了,接着我们看测试代码:

测试代码
public class Calculator {

public static void main(String[] args) {
    //计算表达式
    String expression = "56+2*6-3";
    //分别创建数栈和操作符栈
    ArrayStack numStack = new ArrayStack(10);
    ArrayStack operStack = new ArrayStack(10);
    //定义相关需要的临时变量
    int index = 0; //用于遍历expression的指针
    int num1 = 0; //用于存储从数栈中取出的第一个计算的数字
    int num2 = 0; //用于存储从数栈中取出的第二个计算的数字
    int oper = 0 ; //临时存储从operStack中取出计算的操作符
    int result = 0; //保存我们的计算的结果值
    char ch = ' '; //临时存储从expression中的分割的每一个字符
    String keepNum = ""; //用于拼接多位数的字符

    //循环扫描expression
    while (true){
        //substring(index,index+1) 获取当前index的位置的字符串, charAt(0)转为对应的字符
        ch = expression.substring(index,index+1).charAt(0);
        //判断ch是什么,然后进行相应的处理
        if (operStack.isOper(ch)){ //如果是操作符
            //判断当前符号栈是否为null
            if (!operStack.isEmpty()){ //不为null
                //首先进行比较,如果当前操作符的优先级小于等于operStack中:
                //1. 从numStack取出两个数字
                //1.1. 从operStack中去取出操作符
                //1.2.进行计算,然后将结果入numStack,将当前比较的操作符入operStack即可
                if (operStack.priority(ch) <= operStack.priority(operStack.peek())){
                    num1 = numStack.pop(); //获取第一个计算的数字
                    num2 = numStack.pop(); //获取第二个计算的数字
                    oper = operStack.pop(); //从字符栈中获取操作符
                    //进行计算
                    result = numStack.cal(num1,num2,oper);
                    //将result保存到numStack中
                    numStack.push(result);
                    //将当前的操作符入栈
                    operStack.push(ch);
                }else {
                    //如果当前的操作符的优先级大于operStack中的优先级,直接入栈
                    operStack.push(ch);
                }

            }else {
                //如果当前operStack为null,直接入栈即可
                operStack.push(ch);
            }

        }else {
            //处理多位数字时:
            //1. 不能一扫描到数字就入栈,可能后面还是数字,所以需要我们的index继续向后移动一位,如果时候操作符的话可以入栈了
            keepNum += ch;
            //判断是否已经是expression的最后一个
            if (index == expression.length()-1){
                numStack.push(Integer.parseInt(keepNum));
            }else {
                //判断下一个字符是否是数字,如果是数字的话继续扫描,如果是操作符的话直接入栈
                //index+1 和index+2表示向后看一位不等于index++
                if (operStack.isOper(expression.substring(index + 1, index + 2).charAt(0))) {
                    //入栈
                    numStack.push(Integer.parseInt(keepNum));
                    //注意:将原先的keepNum的值清空
                    keepNum = "";
                }
            }
        }
        //让index +1,判断是否扫描到了expression的最后expression
        index ++;
        if (index >= expression.length()){
            break;
        }
    }
    //当扫描完成时,就顺序从numStack和operStack取出值进行计算操作
    while (true){
        //当我们的operStack中没有了操作符时,就表示我们的numStack中只有一个数字那就是最后的计算结果result
        if (operStack.isEmpty()){
            break;
        }
        num1 = numStack.pop(); //获取第一个计算的数字
        num2 = numStack.pop(); //获取第二个计算的数字
        oper = operStack.pop(); //从字符栈中获取操作符
        //进行计算
        result = numStack.cal(num1,num2,oper);
        //将result保存到numStack中
        numStack.push(result);
    }
    System.out.printf("表达式%s = %d",expression,numStack.pop());
}

来看测试结果如下图:

测试结果.png

从上述结果可以看出时没有问题的,本节所讲的是利用栈实现中缀表达式的计算,关于中缀表达式可以自己百度找找相关资料

上一篇下一篇

猜你喜欢

热点阅读