IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 【数据结构与算法】总结篇:中缀表达式转后缀表达式 与 表达式树 -> 正文阅读

[数据结构与算法]【数据结构与算法】总结篇:中缀表达式转后缀表达式 与 表达式树


一.背景分析:

表达式树是由运算符与操作数组建而成的一颗树(不一定是二叉树),表达式树的树叶为操作数,如常数或者变量名,而其他节点为操作符。如下
就是一颗表达式树:
在这里插入图片描述根据表达式树的前序遍历,中序遍历,后序遍历,我 们分别可以得出常见的三种表达式,前缀表达式,中缀表达式与后缀表达式,
前缀表达式:++abc+defg
后缀表达式:abc
+def+g+
中缀表达式:(a+b * c)+((d*e+f)*g)

二.中缀表达式转化为后缀表达式

在这里我们尝试将中缀表达式转化为后缀表达式
以a+b * c+(d * e+f)*g为例:
转化规则:
1.确立各个字符的优先级: 左右括号 > * / > + -
2.我们可以用一个栈来存储运算符,用一个list来存储输出的值
2.当扫描到左右括号直接入栈,扫描到的是运算符则分为两种情况:
(1)栈顶操作符的优先级小于当前运算符优先级时或者运算符栈为空(如+和-的优先级低于 * 和 /),直接入栈。
(2)栈顶操作符的优先级大于或等于当前运算符优先级且运算符不为空时,循环执行出栈操作并加入list中,直到遇到优先级小于当前运算符的元素为止。循环执行完后再将当前运算符压栈。特别注意的是,只有遇到右括号时,左括号才出栈
(3)在进行符号操作时吗,只有遇到右括号,左括号才会出栈。当遇到右括号循环执行出栈操作,只到左括号被弹出。特别注意:不管是右括号还是弹出的左括号都不执行输出操作。
下面我们就来进行转化演示:
a+b * c+(d * e+f)*g
一开始读到a直接输出,然后是+运算符(此时栈为空)直接入栈。
在这里插入图片描述然后直接将b 入栈,接着扫描到 *,因为+的运算符低于 的运算符,所以 * 直接入栈,紧接着c直接入栈。
在这里插入图片描述接着扫描到了‘+’运算符,因为‘
’运算符比‘+’运算符的优先级高,所以循环执行出栈操作,直到运算符优先级小于‘+’。由于’+'的运算符优先级等于‘+’,所以栈内运算符都被弹出,‘扫描到的+’入栈。
在这里插入图片描述然后遇到左括号,直接入栈。输出d,由于‘( ’括号只有遇到右括号时才会出栈,
所以将 * 入栈。e直接输出
在这里插入图片描述

然后扫描遇到‘+’号,乘号的运算级高于’+‘号,所以称号直接弹出栈输出,’+'号入栈。f 直接入栈
在这里插入图片描述接着遇到右括号,循环执行出栈操作,知道左括号出栈(注意左括号不执行输出)

在这里插入图片描述然后乘号入栈,输出g
在这里插入图片描述最后将剩余元素弹出栈,输出
在这里插入图片描述至此中缀表达式就转化成了后缀表达式

代码演示

public class mum{
    private static int proTest(Character a1){
        if(a1.equals('*')||a1.equals('/'))
        {
            return 1;
        }else if(a1.equals('+')||a1.equals('-')){
            return 0;
        }else{//只能是括号了
            return 2;
        }
    }

    public static void main(String[] args) {
        String str="a+b*c+(d*e+f)*g";
        Stack<Character> stack=new Stack<>();
        List<Character> list=new ArrayList<>();
        Character a;
        //将字符串转化吧为字符数组便于进行操作
        char[] nums=str.toCharArray();
        for (int i = 0; i <nums.length ; i++) {
            char res=nums[i];
            if(Character.isLetterOrDigit(res)){
               list.add(res);
            }else if(nums[i]=='('){
            stack.push(res);
            }else if(nums[i]==')'){
                //如果是右括号则一直出栈,加入到输入的list中,直到左括号出栈
                while(!stack.isEmpty()) {
                    Character c = stack.pop();
                    if (c == '(') {
                        break;
                    }
                    list.add(c);
                }
            }else{//到这里只能是运算符了
                //虽然一开始肯定会有一个数字或者字母入栈,但是也有可能在之前的操作中已经出栈完了
                if(stack.isEmpty()){
                    stack.push(res);
                }else {
                    Character ret = stack.peek();
                    while (!stack.isEmpty()&&proTest(ret) >= proTest(res)) {
                        a = stack.peek();
                        if(a!='(') {
                            list.add(stack.pop());
                        }else{
                            break;
                        }
                    }
                    stack.push(res);
                }
            }

        }
        while(!stack.isEmpty()){
            list.add(stack.pop());
        }

        System.out.println(list);


    }


}

结果验证:
在这里插入图片描述

三.后缀表达式构建表达式树

我们上面已经掌握了中缀表达式转化为后缀表达式,下面我们来聊一聊后缀表达式转化为表达式树的逻辑。其实逻辑并不难。同样是借助一个栈,然后对表达式进行扫描,如果扫描到是是数字或者字符则直接入栈,如果扫描到的是运算符,则弹出栈顶两个元素,重新构造二叉树。重复执行上述操作。
在这里插入图片描述

代码实现

import printer.BinaryTreeInfo;
import printer.BinaryTrees;

import java.util.Scanner;
import java.util.Stack;

class TreeNode{
char val;
TreeNode left;
TreeNode right;

    public TreeNode(char val) {
        this.val = val;
    }
}

public class Operator {
    public static void main(String[] args) {
        Stack<TreeNode>stack=new Stack<>();
        Scanner scan=new Scanner(System.in);
        String str=scan.nextLine();
        char [] ret=str.toCharArray();
        for (int i = 0; i <ret.length; i++) {
            char c=ret[i];
            if(Character.isLetterOrDigit(c)){
                stack.push(new TreeNode(c));
            }else {
                //后序表达式只有运算符和操作数两种情况,没有左右括号
                TreeNode cur1=stack.pop();
                TreeNode cur2=stack.pop();
                TreeNode node=new TreeNode(c);
                stack.push(node);
                node.left=cur2;
                node.right=cur1;
            }

        }
        //二叉树打印方法
        TreeNode res=stack.pop();
        BinaryTrees.println(new BinaryTreeInfo() {
            @Override
            public Object root() {
                return res;
            }

            @Override
            public Object left(Object node) {
                return ((TreeNode)node).left;
            }

            @Override
            public Object right(Object node) {
                return  ((TreeNode)node).right;
            }

            @Override
            public Object string(Object node) {
                return ((TreeNode)node).val;
            }
        });

    }
}

结果测试
在这里插入图片描述二叉树打印工具可以去我的代码仓库看看:二叉树打印

在这里插入图片描述

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-09-15 02:14:52  更:2022-09-15 02:14:55 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/28 18:49:23-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计