数据结构——前缀、中缀、后缀表达式实现和转换(Java)

这篇具有很好参考价值的文章主要介绍了数据结构——前缀、中缀、后缀表达式实现和转换(Java)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.7 前缀、中缀、后缀表达式

1.7.1 概念

  • 它们都是对表达式的记法,因此也被称为前缀记法、中缀记法和后缀记法。它们之间的区别在于运算符相对与操作数的位置不同

    • 前缀表达式的运算符位于与其相关的操作数之前;中缀和后缀同理。
    • 平时我们日常使用并最为熟悉的就是中缀表达式。如:1 + 2 * 3 + 5 / 1 - 5;
    • 后缀表达式又称为逆波兰式
  • 优先级:从大到小是()> */ > ±

  • 一个式子: a(b+c)-d*

    • 中缀表达式(默认):a(b+c)-d*
    • 前缀表达式: *-a+bcd
    • 后缀表达式: *abc+d-

1.7.1 前、中、后缀表达式之间的转换思路

  • 中缀表达式转换为前缀表达式

    ​ 转化的时候先转化优先级大的式子,然后将转化完式子的当做一个整体的操作数来看待,可以将原中缀表达式按照优先级全部加上括号后再转换可能会好理解一点
    比如:a ( b + c ) - d —> ( ( a ( b + c ) - d ) —> - * a + b c d*

  • 中缀表达式转换为后缀表达式

​ 操作步骤与 中缀表达式转前缀表达式差不多。只不过操作符位置变成了2个操作数后面了
​ 比如: a ( b + c ) - d —> a b c + * d -

  • 前缀表达式转换为中缀表达式

    比如:- * a + b c d **
    利用
    栈的思想** 从右向左扫描前缀表达式,扫描到数字入栈扫描到操作符,出栈2数字操作符计算后再将结果入栈,直到表达式扫描结束

  • 后缀表达式转换为中缀表达式

    比如:a b c + * d -
    利用栈的思想左向右扫描前缀表达式,扫描到数字入栈扫描到操作符,出栈2数字操作符计算后再将结果入栈,直到表达式扫描结束

1.7.2 实现逆波兰式计算器(后缀表达式)

思路

  • 1.扫描字符串 将字符挨个加入到一个list<String> ls

  • 2.从左至右扫描后缀表达式ls 遇到数字入堆栈。遇到符号时候弹出栈顶两个数 用运算符对它们进行计算 并将结果入栈 重复上诉过程直到表达式最左端 最后的栈内留下的值就是计算的结果

  • 3.在扫描ls中 需要判断是否为数字 可以使用正则判断(s.matches(“\\d+”)),也可以将字符转化为数字类型再判断

说明

  • 1.逆波兰表达式其实就是后缀表达式
  • 2.本代码目的是为了说明数据结构 在设计上暂时不支持对小数的计算 如果要加上对小数的计算 只要加上对小数的判断即可
  • 3.为了简化扫描表达式的判断 设置后缀表达式字符串数字之间需要空格隔开(不隔开也行,不过这样就需要在扫描的时候额外添加一个多位数字的扫描判断)

​ 比如 : 1 + 2 + 3 + 4 * 5

实现核心代码

扫描字符串加入到列表

    public static List<String> scanExpression(String expression){
        // 扫描字符串表达式 将字符与数字加入到列表内
        List<String> ls = new ArrayList<>();
        String[] s = expression.split(" ");
        Collections.addAll(ls, s);
        return ls;
    }

计算后缀表达式

    public static int PostfixExpressionCalculator(List<String> ls){ // 开始计算后缀表达式
        Stack<String> stack = new Stack<>();
        for (String s: ls){
            if (s.matches("\\d++")){ // 使用正则表达式识别数字字符
                stack.push(s);
                continue;
            }
            String num1 = stack.pop();
            String num2 = stack.pop();
            int result = count1(num1, num2, s);
            stack.push(String.valueOf(result)); // 将运算结果入栈
        }
        return Integer.parseInt(stack.pop());
    }

计算运算符与操作数结果

    public static int count1(String num1,String num2,String p1){ // 遇到符号时的运算
        int n1 = Integer.parseInt(num1);
        int n2 = Integer.parseInt(num2);
        switch (p1){
            case "+": return n1+n2;
            case "-": return n2-n1;
            case "*": return n1*n2;
            case "/": return n2/n1;
            default:
                throw new RuntimeException("出现无法识别的运算符!");
        }
    }

测试表达式String test = “1 2 3 + * 40 -”;

输出结果:
前缀表达式,数据结构与算法,java,数据结构,开发语言
引申

  • 前缀表达式的计算与后缀表达式的计算大同小异,只是扫描表达式的方向变为了从右向左
// 前缀表达式计算函数
    public static int prefixExpressionCalculator(List<String> ls){
        Stack<String> stack = new Stack<>();
        for (int i = ls.size()-1;i>=0;i--){
            String s = ls.get(i);
            if (s.matches("\\d++")){ // 使用正则表达式识别数字字符
                stack.push(s);
                continue;
            }
            // 注意前缀表达式的num1与num2的顺序与后缀表达式 是相反的
            String num1 = stack.pop();
            String num2 = stack.pop();
            int result = count1(num2, num1, s);
            stack.push(String.valueOf(result)); // 将运算结果入栈
        }
        return Integer.parseInt(stack.pop());
    }

测试表达式String test2 = “- * + 2 3 1 4”; // 1(2+3)-4 = 1*

输出结果:
前缀表达式,数据结构与算法,java,数据结构,开发语言
中缀表达式的计算器实现在另外一片文章内已经写好了
https://blog.csdn.net/m0_52861211/article/details/129865965?spm=1001.2014.3001.5502

1.7.3 中缀表达式转化为后缀表达式

​ 对于人类来说,中缀表达式的计算是很符合思考逻辑的。但是对于计算机来说,中缀表达式的计算相比后缀表达式和前缀表达的计算很是繁琐,所以我们可以先设计方法将中缀表达式转化为后缀表达式/前缀表达式再计算

思路
前缀表达式,数据结构与算法,java,数据结构,开发语言
前缀表达式,数据结构与算法,java,数据结构,开发语言
实现代码

返回运算符的优先级

    public static int checkOrder(String str){   // 返回运算符的优先级
        switch (str) {
            case "/":
            case "*" : return 2;
            case "-":
            case "+" : return 0;
            default : return -1;
        }
    }

判断字符是否是运算符

  public static boolean isOperator(String operator){ // 判断字符是否是运算符
        return ("+".equals(operator)||"-".equals(operator)||"*".equals(operator)||"/".equals(operator));
    }

将中缀表达式转换为后缀表达式

   // 实现中缀表达式转化为后缀表达式
    // 因为s2这个栈 在整个过程中没有弹出栈的操作,而且最终结果是s2栈的逆序输出结果 所以可以使用list来代替栈实现 简化输出
    public static List<String> Infix2PostfixExpression(String str){
        // 1. 扫描表达式
        List<String> ls = scanExpression(str);
        // 2. 初始化s1 s2
        Stack<String> s1 = new Stack<>(); // 运算符栈
        List<String> s2 = new ArrayList<>();    // 结果集合
        // 3. 开始转化
        for(String tempS : ls){
            // 3.1操作数直接入s2
            if (tempS.matches("\\d+")){
                s2.add(tempS);
            } else if (isOperator(tempS)) { // 3.2 遇到运算符
                while (true){
                    // 栈空或栈顶元素为 ( ,直接将当前符号入栈
                    if (s1.isEmpty()||s1.peek().equals("(")){
                        s1.push(tempS);
                        break;
                    }
                    if (checkOrder(tempS) > checkOrder(s1.peek())){ // 优先级大于栈顶运算符,入栈
                        s1.push(tempS);
                        break;
                    }// 否则 s1栈顶弹出压入s2 重新判断与新栈顶的优先级
                    String pop = s1.pop();
                    s2.add(pop);
                }
            }else{ // 3.3 遇到括号
                if ("(".equals(tempS)){ // 遇到左括号 直接压入s1
                    s1.push(tempS);
                }else if (")".equals(tempS)){ // 遇到右括号
                    // 依次弹出s1栈顶的运算符,并压入s2 直到遇到栈顶元素为左括号为止 最后把这一对括号都丢弃
                    while (!"(".equals(s1.peek())){
                        s2.add(s1.pop());
                    }
                    s1.pop(); // 将右括号弹出
                }else
                    throw new RuntimeException("输入运算符有误!无法识别!");
            }
        }
        // 在表达式扫描完毕后 将s1中剩余的运算符依次弹出并压入s2
        while (s1.size() != 0)
             s2.add(s1.pop());
        // s2顺序输出就是转换后的后缀表达式了
        return s2;
    }

1.7.4 全部完整代码与输出结果

代码

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

public class PostfixExpressionCalculatorDemo {
    public static List<String> scanExpression(String expression){
        // 扫描字符串表达式 将字符与数字加入到列表内
        List<String> ls = new ArrayList<>();
        String[] s = expression.split(" ");
        Collections.addAll(ls, s);
        return ls;
    }
    // 实现中缀表达式转化为后缀表达式
    // 因为s2这个栈 在整个过程中没有弹出栈的操作,而且最终结果是s2栈的逆序输出结果 所以可以使用list来代替栈实现 简化输出
    public static List<String> Infix2PostfixExpression(String str){
        // 1. 扫描表达式
        List<String> ls = scanExpression(str);
        // 2. 初始化s1 s2
        Stack<String> s1 = new Stack<>(); // 运算符栈
        List<String> s2 = new ArrayList<>();    // 结果集合
        // 3. 开始转化
        for(String tempS : ls){
            // 3.1操作数直接入s2
            if (tempS.matches("\\d+")){
                s2.add(tempS);
            } else if (isOperator(tempS)) { // 3.2 遇到运算符
                while (true){
                    // 栈空或栈顶元素为 ( ,直接将当前符号入栈
                    if (s1.isEmpty()||s1.peek().equals("(")){
                        s1.push(tempS);
                        break;
                    }
                    if (checkOrder(tempS) > checkOrder(s1.peek())){ // 优先级大于栈顶运算符,入栈
                        s1.push(tempS);
                        break;
                    }// 否则 s1栈顶弹出压入s2 重新判断与新栈顶的优先级
                    String pop = s1.pop();
                    s2.add(pop);
                }
            }else{ // 3.3 遇到括号
                if ("(".equals(tempS)){ // 遇到左括号 直接压入s1
                    s1.push(tempS);
                }else if (")".equals(tempS)){ // 遇到右括号
                    // 依次弹出s1栈顶的运算符,并压入s2 直到遇到栈顶元素为左括号为止 最后把这一对括号都丢弃
                    while (!"(".equals(s1.peek())){
                        s2.add(s1.pop());
                    }
                    s1.pop(); // 将右括号弹出
                }else
                    throw new RuntimeException("输入运算符有误!无法识别!");
            }
        }
        // 在表达式扫描完毕后 将s1中剩余的运算符依次弹出并压入s2
        while (s1.size() != 0)
             s2.add(s1.pop());
        // s2顺序输出就是转换后的后缀表达式了
        return s2;
    }
    public static int PostfixExpressionCalculator(List<String> ls){ // 开始计算后缀表达式
        Stack<String> stack = new Stack<>();
        for (String s: ls){
            if (s.matches("\\d++")){ // 使用正则表达式识别数字字符
                stack.push(s);
                continue;
            }
            String num1 = stack.pop();
            String num2 = stack.pop();
            int result = count1(num1, num2, s);
            stack.push(String.valueOf(result)); // 将运算结果入栈
        }
        return Integer.parseInt(stack.pop());
    }
    public static int prefixExpressionCalculator(List<String> ls){
        Stack<String> stack = new Stack<>();
        for (int i = ls.size()-1;i>=0;i--){
            String s = ls.get(i);
            if (s.matches("\\d++")){ // 使用正则表达式识别数字字符
                stack.push(s);
                continue;
            }
            // 注意前缀表达式的num1与num2的顺序与后缀表达式 是相反的
            String num1 = stack.pop();
            String num2 = stack.pop();
            int result = count1(num2, num1, s);
            stack.push(String.valueOf(result)); // 将运算结果入栈
        }
        return Integer.parseInt(stack.pop());
    }
    public static int count1(String num1,String num2,String p1){ // 遇到符号时的运算
        int n1 = Integer.parseInt(num1);
        int n2 = Integer.parseInt(num2);
        switch (p1){
            case "+": return n1+n2;
            case "-": return n2-n1;
            case "*": return n1*n2;
            case "/": return n2/n1;
            default:
                throw new RuntimeException("出现无法识别的运算符!");
        }
    }
    public static int checkOrder(String str){   // 返回运算符的优先级
        switch (str) {
            case "/":
            case "*" : return 2;
            case "-":
            case "+" : return 0;
            default : return -1;
        }
    }
    public static boolean isOperator(String operator){ // 判断字符是否是运算符
        return ("+".equals(operator)||"-".equals(operator)||"*".equals(operator)||"/".equals(operator));
    }
    public static void main(String[] args) {
        // 后缀表达式1
        String test = "1 2 3 + * 40 -";  // 1*(2+3)-40 = -35
        // 前缀表达式2
        String test2 = "- * + 2 3 1 4"; // 1*(2+3)-4 = 1
        // 中缀表达式3
        String test3 = "1 + ( ( 2 + 3 ) * 4 ) - 5";   // 16
        List<String> ls = scanExpression(test);
        List<String> ls2 = scanExpression(test2);
        System.out.println("后缀表达式1: "+PostfixExpressionCalculator(ls));
        System.out.println("前缀表达式2: "+prefixExpressionCalculator(ls2));
        System.out.println("test3: "+PostfixExpressionCalculator(Infix2PostfixExpression(test3)));
    }
 }

输出结果
前缀表达式,数据结构与算法,java,数据结构,开发语言文章来源地址https://www.toymoban.com/news/detail-751526.html

到了这里,关于数据结构——前缀、中缀、后缀表达式实现和转换(Java)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C++ 数据结构 栈 中缀表达式转后缀表达式并求值

    写在前面,这里用的是我自己写的Stack类,并非STL,实现方法为静态数组,但使用过程中的函数方法一样,无伤大雅。(完整code和Stack_static类赋在最后) 1.从左到右遍历 2.数,即参与运算数,直接放进后缀表达式之后 3.左括号 ,直接压入栈(因为括号的优先级最高,无需判断

    2024年02月03日
    浏览(37)
  • 算术表达式:前缀、中缀表、后缀表达式相互转换

    概念: 三者的区别在于运算符相对于操作数的位置有所不同   前缀表达式 前缀表达式是一种没有括号的算术表达式,与中缀表达式不同的是,其将运算符写在前面,操作数写在后面。   中缀表达式  中缀表达式是一种通用的算术或逻辑公式表示方法,操作符以中缀形式处于

    2024年02月05日
    浏览(76)
  • 【数据结构】超详细讲解:算术表达式转化为后缀表达式、前缀表达式、表达式树的构建

    作者: 努力学习的大一在校计算机专业学生,热爱学习和创作。目前在学习和分享:算法、数据结构、Java等相关知识。 博主主页: @是瑶瑶子啦 所属专栏: 【数据结构】:该专栏专注于数据结构知识,持续更新,每一篇内容优质,浅显易懂,不失深度! 近期目标: 写好专栏

    2024年02月08日
    浏览(41)
  • 数据结构 | 栈的中缀表达式求值

    目录 什么是栈? 栈的基本操作 入栈操作 出栈操作 取栈顶元素 中缀表达式求值 实现思路 具体代码 栈是一种线性数据结构,具有“先进后出”(Last In First Out, LIFO)的特点。它可以看作是一种受限的线性表,只能在表的一端进行插入和删除操作,这一端被称为栈顶,另一端

    2024年02月02日
    浏览(42)
  • 数据结构 | 后缀表达式【深入剖析堆栈原理】

    Hello,大家好,国庆的第二天,带来的是数据结构中堆栈部分的后缀表达式,这也是一块有关栈的应用方面困扰了众多同学的一个大难题,今天就让我们一起解决这个难题📕 后缀表达式也称为 逆波兰表达式 ,也就是将算术运算符放在操作数的后面 例如【1 + 2 * 3】的后缀表达

    2023年04月27日
    浏览(36)
  • 中缀表达式转后缀表达式

      一种不需要括号的后缀表达法,也把它称为 逆波兰 表示,是波兰逻辑学家卢卡西维奇(Lukasiewicz)发明的一种表示表达式的方法。   中缀表达式指的是“9+(3-1)×3+8÷2”,这种就是我们通常见到的书写算式顺序,要计算中缀表达式则首先要将字符串转换为后缀表达式,即

    2023年04月08日
    浏览(36)
  • 【数据结构】一篇文章带你彻底学会《后缀表达式》

    创作不易,本篇文章如果帮助到了你,还请点赞 关注支持一下♡𖥦)!! 主页专栏有更多知识,如有疑问欢迎大家指正讨论,共同进步! 🔥c语言系列专栏:c语言之路重点知识整合 🔥 给大家跳段街舞感谢支持!ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ 后缀表

    2024年02月05日
    浏览(46)
  • 数据结构与算法-(7)---栈的应用-(4)后缀表达式求值

    🌈write in front🌈 🧸大家好,我是Aileen🧸.希望你看完之后,能对你有所帮助,不足请指正!共同学习交流. 🆔本文由Aileen_0v0🧸 原创 CSDN首发🐒 如需转载还请通知⚠️ 📝个人主页:Aileen_0v0🧸—CSDN博客 🎁欢迎各位→点赞👍 + 收藏⭐️ + 留言📝​ 📣系列专栏:Aileen_0v0🧸

    2024年02月07日
    浏览(40)
  • 【夜深人静学数据结构与算法 | 第二篇】后缀(逆波兰)表达式

    目录 前言:  中缀表达式:  后缀表达式: 中缀表达式转后缀表达式: 后缀表达式计算结果: 总结:  计算机在计算四则运算的时候,由于括号以及运算优先级的存在,并不能够很好的处理所有的运算,为了处理这种情况,我们引入了后缀表达式来优化算法。         

    2024年02月13日
    浏览(40)
  • 中缀表达式转后缀表达式,使用逆波兰计算。可以计算小数

    传递一个分开保存符号与数字的List即可:List SumNumber; 获取参数的构造方法如下: 要求的List保存数据的方式如下: 例如:1+2+3 然后使用 EvaluatePostfixExpressions 方法传递出一个保存好结果的String。

    2024年02月15日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包