JAVA 应用栈对RPN逆波兰表达式求值

109 篇文章 0 订阅
14 篇文章 1 订阅

RPN逆波兰表达式(后缀表达式)

逆波兰表达式,它的语法规定,表达式必须以逆波兰表达式的方式给出。逆波兰表达式又叫做后缀表达式。这个知识点在数据结构和编译原理这两门课程中都有介绍,下面是一些例子:
正常的表达式 逆波兰表达式

a+b ---> a,b,+
a+(b-c) ---> a,b,c,-,+
a+(b-c)*d ---> a,b,c,-,d,*,+
a+d*(b-c)--->a,d,b,c,-,*,+
a=1+3 ---> a,1,3,+,=

用途
逆波兰表达式是一种十分有用的表达式,它将复杂表达式转换为可以依靠简单的操作得到计算结果的表达式。例如(a+b)(c+d)转换为ab+cd+

逆波兰表达式

定义很清楚,那么表达式:12*(3+4)-6+8/2 ,我们可以转换为:12 3 4 + * 6 - 8 2 / + ,既然将其转换为了逆波兰表达式,那么有该如何进行求值,这里,应用栈就可以特别方便的将其求出,其思路便是,将数字入栈,遇到算术操作符,取出前两个入栈的数字进行运算,在再将结果入栈。将12 3 4 + * 6 - 8 2 / +分步操作。

将 12 3 4入栈

这里写图片描述
遇到算数操作符 “+”,将 3 4 取出,相加得 7,将结果7入栈,而后再遇“*”,再将 7 12 取出相乘 结果为 84
这里写图片描述

将 84 入栈,其后的是数字6,将其入栈,接下来是算术操作符 “-”,取出 6 84
计算 84 -6
这里写图片描述
将结果78入栈,随后是数字8和2,分别入栈,然后又遇到算术操作符 “/”
这里写图片描述
将 2 和8取出,计算结果为4,入栈,再往后走,遇到了操作符“+”,那么再将4和78取出相加
这里写图片描述
最后将计算结果82入栈,那么当所有操作结束,栈中所存的元素便是我们计算所得的最终结果。
这里写图片描述

代码

    package stack;

interface Stack {
void stackPush(Object obj);
void stackPop();
int stackSize();
Object stackTop();
void printLink();
}

class Factory {// 工厂模式实例化StackImpl类
private Factory() {
}

public static Stack getLinkInstance() {
    return new StackImpl();
}
}

class StackImpl implements Stack {// 继承了Stack接口的方法,通过向上转型,产生实例化对象
private int size = 0;// Stack入栈元素的数量
private Node first;// 栈底,
private Node last;// 栈顶

private class Node {// 产生节点的内部类
    private Object item;// 存放入栈元素
    private Node next;// 放下一次要入栈的节点

    private Node(Object item, Node next) {// 构造方法
        this.item = item;
        this.next = next;
    }
}

@Override
public void stackPush(Object obj) {// 入栈方法
    Node tmp = this.first;
    Node newnode = new Node(obj, null);
    this.last = newnode;
    if (this.first == null) {// 第一次入栈,设栈底
        this.first = newnode;
    } else {
        while (null != tmp.next) {// 非第一次入栈,遍历找栈顶,入栈
            tmp = tmp.next;
        }
        tmp.next = newnode;
    }
    this.size++;// 记得扩充元素数量
}

@Override
public void stackPop() {// 出栈
    Node tmp = this.first;
    if(null ==tmp.next) {//当栈中只有一个元素时,直接清空栈
        this.first = null;
        this.last = null;
        this.size = 0;
        return;
    }
    while (null != tmp.next.next) {// 遍历栈,找离栈顶一个节点的节点
        tmp = tmp.next;
    }
    this.last = tmp;// 重设栈顶
    tmp.next = null;
    this.size--;
}

@Override
public int stackSize() {// 获取当前栈中节点数(元素数量)
    return this.size;
}

@Override
public Object stackTop() {// 获取栈顶元素
    return this.last.item;
}

@Override
public void printLink() {// 辅助方法,查看当前栈中的所有元素
    Node tmp = this.first;
    while (null != tmp) {
        System.out.println(tmp.item);
        tmp = tmp.next;
    }
}
}


public class Test {
public static void main(String[] args) {
    Stack stack = Factory.getLinkInstance();//调用工厂类get方法,产生一个StackImpl类实例,向上转型实现Stack接口
    String str = "12 3 4 + * 6 - 8 2 / +";
    RPN(str, stack);//逆波兰表达式求值方法
    //+++++++++++++++++++++++
    //测试入栈
//      stack.stackPush(1);
//      stack.stackPush("2");
//      stack.stackPush("3");
//      stack.stackPush("4");
//      stack.stackPush("5");
//      stack.stackPush("6");
//      stack.printLink();
//      System.out.println("++++++++++++++++++++++++++");
//      //+++++++++++++++++++++++++++++++++
//      //测试出栈
//      // link.stackPop();
//      stack.printLink();
//      System.out.println("++++++++++++++++++++++++++");
//      //+++++++++++++++++++++++++++++++++
//      //测试获取栈顶元素和元素数量
//      System.out.println(stack.stackTop());
//      System.out.println(stack.stackSize());
}
public static void RPN(String str,Stack stack) {
    int left = 0;//用来计算的左值
    int right = 0;//用来计算的由值
    char [] strarr = new char [str.length()];//创建一个字符数组,长度str.length()获取字符串str的字符串长度
    strarr = str.toCharArray();//这里的toCharArray()方法将字符串转为字符数组
    int num = 0;//用来存转换后的数字
    for (int i = 0; i <strarr.length; i ++ ) {//遍历
        while (' ' != strarr[i] && i < strarr.length && '0' <= strarr[i] && strarr[i] <= '9') {// "12 3 4 + * 6 - 8 2 / +";
            //过滤,只留数字字符进入
            num = num * 10 + strarr[i]-'0';//转化,字符数字与数字ASCII码差48,即'0'
            i++;//这个i就是for中的i,大家同步走
        }
        if (' ' == strarr[i] && '0' <= strarr[i-1] && strarr[i-1] <= '9') {//当前为空格,且前一个是数字字符(可能为+-..)
            stack.stackPush(num);//关键操作,把数字入栈
        }
        num = 0;//清空,不然后果很严重
        // String s = String.valueOf('c'); //效率最高的方法,字符转字符串
        switch (strarr[i]) {//是算术操作符,进入计算
        case '+':{
            right = Integer.parseInt(stack.stackTop().toString() ) ;//对象转int,先转为字符串,再转为数字Object o ;Integer.praseInt(o==null?"":o.toString())
            //栈顶返回值是对象,采用曲线救国的方式,先转成字符串,在转为数字
            stack.stackPop();//将已经使用过的元素出栈
            left = Integer.parseInt(stack.stackTop().toString() ) ;
            stack.stackPop();
            stack.stackPush(left+right);//将计算结果入栈
        }
            break;
        case '-':{
            right = Integer.parseInt(stack.stackTop().toString() ) ;
            stack.stackPop();
            left = Integer.parseInt(stack.stackTop().toString() ) ;
            stack.stackPop();
            stack.stackPush(left-right);
        }
            break;
        case '*':{
            right = Integer.parseInt(stack.stackTop().toString() ) ;//对象转int,先转为字符串,再转为数字Object o ;Integer.praseInt(o==null?"":o.toString())
            stack.stackPop();
            left = Integer.parseInt(stack.stackTop().toString() ) ;
            stack.stackPop();
            stack.stackPush(left*right);
        }
            break;
        case '/':{
            right = Integer.parseInt(stack.stackTop().toString() ) ;//对象转int,先转为字符串,再转为数字Object o ;Integer.praseInt(o==null?"":o.toString())
            stack.stackPop();
            left = Integer.parseInt(stack.stackTop().toString() ) ;
            stack.stackPop();
            try {//异常处理,right可能为零
                left = left/right;
                stack.stackPush(left);
            } catch (Exception e) {
                // TODO: handle exception
                e.printStackTrace();//啥都不写
            }

        }
            break;

        default:
            break;
        }

//          System.out.println(Integer.parseInt(stack.stackTop().toString() ));//检测每次入栈情况
    }
    System.out.println(Integer.parseInt(stack.stackTop().toString() ));
    }
}

这里的栈的构造参见>JAVA实现动态栈<,在每行代码后面都做了详细的注释,这里的代码也一样,但是由于里面加入了逆波兰表达式求值的方法,所以看起来难免会觉得乱,>源码已上传Github<,如果觉得JAVA语言看起来太乱,可以参考>C语言应用栈实现逆波兰表达式求值(动态栈和求值源码)<

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值