数据结构(Java)学习笔记——知识点:前缀、中缀、后缀表达式

文章介绍了数据结构中前缀(波兰表达式)、中缀和后缀(逆波兰表达式)表达式的基本概念,并提供了Java代码实现逆波兰计算器。中缀表达式通常用于人类阅读,而计算通常使用后缀表达式。文章还详细阐述了中缀表达式转后缀表达式的步骤,并给出相关代码示例。
摘要由CSDN通过智能技术生成

八、前、中、后缀表达式

1、前缀表达式(波兰表达式)

 a、前缀表达式的运算符位于操作数之前
 b、举例:( 3 + 4 ) * 5 - 6 对应的前缀表达式应为为 - * + 3 4 5 6
 
 在前缀表达式中,是从右至左扫描表达式,遇到数字时,将数字压入堆栈遇到运算符时,弹出栈顶的两个数,用运算符对他们进行相应的计算(栈顶元素和次栈顶元素),并将结果入栈;重复上述过程,直到表达式的最左端,最后算出的值就是表达式的结果。
 
 上述表达式求值的步骤如下
 Ⅰ、从右至左扫描,将 6、5、4、3 压入堆栈。
 Ⅱ、遇到 + 运算符,弹出 3 和 4 (3 为栈顶元素,4为次栈顶元素),计算出 3 + 4 的结果, 为 7,再将 7 入栈。
 Ⅲ、接下来进行 * 的运算,弹出 7 和 5 ,计算出得 7 * 5 = 35,再将 35 入栈。
 Ⅳ、最后时 - 运算符,计算出 35 - 6 的值,得到29,输出最终结果。

2、中缀表达式

 中缀表达式,就是我们人看到的数学表达式,例:( 3 + 4 ) * 5 - 6 。对人类友好,对二进制的硅基大脑是不友好的。在计算时,一般都转换成后缀表达式进行操作。

3、后缀表达式(逆波兰表达式)

 a、后缀表达式与前缀表达式相似,就是运算符位于操作数之后。
 b、举例:( 3 + 4 ) * 5 - 6 对应的后缀表达式是 3 4 + 5 * 6 -
 c、再比如
 在这里插入图片描述
 在后缀表达式中,是从左至右扫描表达式,遇到数字时,将数字压入堆栈遇到运算符时,弹出栈顶的两个数,用运算符对他们进行相应的计算(栈顶元素和次栈顶元素),并将结果入栈;重复上述过程,直到表达式的最右端,最后算出的值就是表达式的结果。
 
 上述表达式求值的步骤如下
 Ⅰ、从左至右扫描,将 3 和 4 压入堆栈。
 Ⅱ、遇到 + 运算符,弹出 4 和 3 (4 为栈顶元素,3为次栈顶元素),计算出 3 + 4 的结果, 为 7,再将 7 入栈。
 Ⅲ、将 5 压入栈
 Ⅳ、接下来进行 * 的运算,弹出 5 和 7 ,计算出得 7 * 5 = 35,再将 35 入栈。
 Ⅴ、将6入栈
 Ⅵ、最后时 - 运算符,计算出 35 - 6 的值,得到29,输出最终结果。(注意!此时注意减数和被减数的顺序!!!)

4、逆波兰计算器

需求如下

 1)输入一个逆波兰表达式(后缀表达式),使用栈(Stack),计算结果
 2)支持小括号和多位数整数,这里只做简易的计算,所以只用整数就行。
 3)思路分析
 4)完成代码
 
 一个小时的头脑风暴下,我终于写了出来。方法不唯一,这里我只写了和上一段代码相似的代码。其实也可以用内置剪切方法 split()来写。

代码实现

package com.database.stack;

public class PolandNotation {
    public static void main(String[] args) {
        //首先定义一个计算公式
        //(3+4)*5-6 => 3 4 + 5 * 6 -
        String suffixExpression = "3 4 + 5 * 6 - ";
        Poland poland = new Poland(suffixExpression.length());
        int index = 0;//定义一个下标
        int num1 = 0;
        int num2 = 0;
        int res = 0;
        char ch = ' ';
        String str = "";
        while(true){
            //跳出循环
            if(index >= suffixExpression.length()){
                break;
            }
            ch = suffixExpression.substring(index,index + 1).charAt(0);
            if(ch == ' '){
                index++;
                continue;
            }else{
                if(!poland.isOper(ch)){
                    //插入数字
                    if(str == ""){
                        str += ch;
                    }
                    //判断如果下一个元素不是符号
                    if(!poland.isOper(suffixExpression.substring(index + 1,index + 2).charAt(0))){
                        //如果不是符号,就拼接到str后面
                        str += ch;
                        index++;
                        continue;
                    }
                    poland.push(Integer.parseInt(str));
                    str = "";
                }else{
                    //如果是符号,就取出刚刚入栈的数,进行计算,然后再放入栈中
                    num1 = poland.pop();
                    num2 = poland.pop();
                    res = poland.cal(num1,num2,ch);
                    poland.push(res);
                }
            }
            index++;
        }
        System.out.println("最终计算结果为:" + res);
    }
}
class Poland{
    private int maxSize;//栈的大小
    private int[] stack;//定义一个数组,因为我们要用数组来实现栈。
    private int top = -1;//初始状态下,将top置于数组的顶端。
    //编写一个构造器,声明变量的同时就生成长度

    public Poland(int maxSize){
        this.maxSize = maxSize;
        stack = new int[maxSize];//根据maxSize来生成一个数组
    }

    //判断栈满,因为栈是从下标为0开始的,所以栈满时正好是 maxSize - 1
    public boolean isFull(){
        return top == maxSize - 1;
    }

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

    //入栈 push
    public void push(int value){
        if (isFull()){
            System.out.println("栈是满的!");
            return ;
        }
        top++;//top先自加再往里面填值
        stack[top] = value;
    }

    //出站 pop
    public int pop(){
        int value = 0;
        if(isEmpty()){
            System.out.println("栈是空的!");
            return 0;
        }
        value = stack[top];
        top--;
        return value;
    }

    //遍历栈的时候是从栈顶开始遍历的 栈顶的下标值为top
    public void list(){
        if(isEmpty()){
            System.out.println("栈是空的!");
            return ;
        }
        for(int i = top; i >= 0; i--){
            System.out.println( stack[i] + " ");
        }
    }

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

    //一个计算方法
    public int cal(int num1, int num2, char oper){
        int res = 0;//定义一个res接收结果
        switch (oper){
            case '+':
                res = num1 + num2;
                break;
            case '-'://注意顺序
                res = num2 - num1;
                break;
            case '*':
                res = num1 * num2;
                break;
            case '/':
                res = num1 / num2;
                break;
            default:
                break;
        }
        return res;
    }
}

运行结果

在这里插入图片描述

5、中缀表达式转后缀表达式

具体步骤

 1)初始化两个栈:运算符栈s1和存储中间结果的栈s2
 2)从左到右扫描中缀表达式
 3)遇到数字,压入s2
 4)遇到运算符比较其与s1栈顶运算符的优先级
  a、如果s1为空,或栈顶运算符为"(",则直接把此运算符入栈。
  b、否则,如果优先级比栈顶运算符的高,也将此运算符入栈。
  c、否则,将s1栈顶的运算符弹出,并压入到s2中,再次转到4-a中与s1中的栈顶运算符相比较。
 5)如果遇到括号时:
  a、如果时左括号“(”,则直接压入s1
  b、如果时右括号“)”,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃
 6)重复步骤2到5,直到表达式的最右边
 7)将s1中剩余的运算符依次弹出并压入s2
 8)依次弹出s2中的元素并输出,结果的逆序就是中缀表达式对应的后缀表达式

 举例:1 + ( ( 2 + 3 ) * 4 ) - 5 ==>  1 2 3 + 4 * + 5 -
在这里插入图片描述

代码实现

package com.database.stack;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class PolandNotation {
    public static void main(String[] args) {
        //完成将一个中缀表达式转后缀表达式的功能
        //说明
        //1、1+((2+3)*4)-5 => 1 2 3 + 4 * + 5 -
        String infixExpriession = "1+((2+3)*4)-5";
        InfixExpression s1 = new InfixExpression(infixExpriession.length());
        InfixExpression s2 = new InfixExpression(infixExpriession.length());
        int subscript = 0;
        char element = ' ';
        String number = "";
        while(true){
            //如果遍历到最后一个数,直接跳出循环
            if(subscript >= infixExpriession.length()){
                break;
            }
            element = infixExpriession.substring(subscript,subscript + 1).charAt(0);

            if(s1.isOper(element)){
                //如果element的值是一个运算符
                //如果s1为空,或栈顶运算符为"(",则直接把此运算符入栈。
                if(s1.isEmpty() || s1.peek() == '('){
                    s1.push(element);
                }else if(s1.priority(element) > s1.priority(s1.peek())){
                    //否则,如果优先级比栈顶运算符的高,也将此运算符入栈。
                    s1.push(element);
                }else{
                    //否则,将s1栈顶的运算符弹出,并压入到s2中,再次转到4-a中与s1中的栈顶运算符相比较。
                    s2.push(s1.pop());
                    continue;
                }
            }else if(s1.isBracket(element)){
                //如果输入的是括号
                if(element == '('){
                    //如果是左括号
                    s1.push(element);
                }else{
                    //如果时右括号“)”,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号**丢弃**
                    while (true){
                        if(s1.peek() == '('){
                            s1.pop();
                            break;
                        }
                        s2.push(s1.pop());
                    }
                }
            }else{
                //如果element的值是一个数字,压入s2
                if(number == ""){
                    number += element;
                }
                //如果运行到最后一个字符的时候
                if(subscript == infixExpriession.length() - 1){
                    s2.push(Integer.parseInt(number));
                    break;
                }
                if(!s2.isOper(infixExpriession.substring(subscript + 1,subscript +2).charAt(0))){
                    if(!s2.isBracket(infixExpriession.substring(subscript + 1,subscript +2).charAt(0))){
                        number += element;
                        subscript++;
                        continue;
                    }
                }
                s2.push(Integer.parseInt(number));
                number = "";
                //s2.push(element);
            }
            subscript++;
        }

        //将s1中剩余的运算符依次弹出并压入s2
        while(true){
            if(s1.isEmpty()){
                break;
            }
            s2.push(s1.pop());
        }

        //定义一个数组
        List<Object> list = new ArrayList<Object>();
        while(true) {
            if (s2.isEmpty()) {
                break;
            }
            int temp = s2.pop();

            if((temp + '0') < 60){
                list.add((char)(temp + '0'));
                continue;
            }
            list.add((char)temp);
        }

        //倒序输出
        Collections.reverse(list);
        System.out.println("生成的后缀表达式为:" + list);


        //首先定义一个计算公式
        //(3+4)*5-6 => 3 4 + 5 * 6 -
        String suffixExpression = "3 4 + 5 * 6 - ";
        Poland poland = new Poland(suffixExpression.length());
        int index = 0;//定义一个下标
        int num1 = 0;
        int num2 = 0;
        int res = 0;
        char ch = ' ';
        String str = "";
        while(true){
            //跳出循环
            if(index >= suffixExpression.length()){
                break;
            }
            ch = suffixExpression.substring(index,index + 1).charAt(0);
            if(ch == ' '){
                index++;
                continue;
            }else{
                if(!poland.isOper(ch)){
                    //插入数字
                    if(str == ""){
                        str += ch;
                    }
                    //判断如果下一个元素不是符号
                    if(!poland.isOper(suffixExpression.substring(index + 1,index + 2).charAt(0))){
                        //如果不是符号,就拼接到str后面
                        str += ch;
                        index++;
                        continue;
                    }
                    poland.push(Integer.parseInt(str));
                    str = "";
                }else{
                    //如果是符号,就取出刚刚入栈的数,进行计算,然后再放入栈中
                    num1 = poland.pop();
                    num2 = poland.pop();
                    res = poland.cal(num1,num2,ch);
                    poland.push(res);
                }
            }
            index++;
        }
        System.out.println("最终计算结果为:" + res);
    }
}

class InfixExpression{
    private int maxSize;//栈的大小
    private int[] stack;//定义一个数组,因为我们要用数组来实现栈。
    private int top = -1;//初始状态下,将top置于数组的顶端。

    //构造器
    public InfixExpression(int maxSize){
        this.maxSize= maxSize;
        stack = new int[maxSize];
    }

    //判断栈满,因为栈是从下标为0开始的,所以栈满时正好是 maxSize - 1
    public boolean isFull(){
        return top == maxSize - 1;
    }

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

    //怎加一个,返回栈顶的值的方法
    public int peek(){
        return stack[top];
    }

    //入栈 push
    public void push(int value){
        if (isFull()){
            System.out.println("栈是满的!");
            return ;
        }
        top++;//top先自加再往里面填值
        stack[top] = value;
    }

    //出站 pop
    public int pop(){
        int value = 0;
        if(isEmpty()){
            System.out.println("栈是空的!");
            return 0;
        }
        value = stack[top];
        top--;
        return value;
    }

    //判断运算符优先级的方法,数字越大,优先级越高
    public int priority(int oper){
        if(oper == '*' || oper == '/'){
            return 1;
        }else if(oper == '+' || oper == '-'){
            return 0;
        }else{
            return -1;
        }//目前假定只有 + - * / 这四个运算
    }

    //遍历栈的时候是从栈顶开始遍历的 栈顶的下标值为top
    public void list(){
        if(isEmpty()){
            System.out.println("栈是空的!");
            return ;
        }
        for(int i = top; i >= 0; i--){
            System.out.println( stack[i] + " ");
        }
    }

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

    //判断是否为括号
    public boolean isBracket(char val){
        return val == ')' || val == '(';
    }
}

class Poland{
    private int maxSize;//栈的大小
    private int[] stack;//定义一个数组,因为我们要用数组来实现栈。
    private int top = -1;//初始状态下,将top置于数组的顶端。
    //编写一个构造器,声明变量的同时就生成长度

    public Poland(int maxSize){
        this.maxSize = maxSize;
        stack = new int[maxSize];//根据maxSize来生成一个数组
    }

    //判断栈满,因为栈是从下标为0开始的,所以栈满时正好是 maxSize - 1
    public boolean isFull(){
        return top == maxSize - 1;
    }

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

    //入栈 push
    public void push(int value){
        if (isFull()){
            System.out.println("栈是满的!");
            return ;
        }
        top++;//top先自加再往里面填值
        stack[top] = value;
    }

    //出站 pop
    public int pop(){
        int value = 0;
        if(isEmpty()){
            System.out.println("栈是空的!");
            return 0;
        }
        value = stack[top];
        top--;
        return value;
    }

    //遍历栈的时候是从栈顶开始遍历的 栈顶的下标值为top
    public void list(){
        if(isEmpty()){
            System.out.println("栈是空的!");
            return ;
        }
        for(int i = top; i >= 0; i--){
            System.out.println( stack[i] + " ");
        }
    }

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

    //一个计算方法
    public int cal(int num1, int num2, char oper){
        int res = 0;//定义一个res接收结果
        switch (oper){
            case '+':
                res = num1 + num2;
                break;
            case '-'://注意顺序
                res = num2 - num1;
                break;
            case '*':
                res = num1 * num2;
                break;
            case '/':
                res = num1 / num2;
                break;
            default:
                break;
        }
        return res;
    }
}

 这段代码是有毛病的,只能运算解析9以内的表达式。可以用转换数组的方式进行完善,这里主要是描述思路,请有空闲时间自行完成。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

宇直不会放弃

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值