栈的数据结构完成表达式(5*10+2-7+5)/10+5的计算

news2024/11/26 22:52:20

栈(Stack)是一种线性数据结构,具有后进先出(LIFO)的特性。它可以理解为一种类似于抽屉的容器,只能在顶部进行插入和删除操作,其他位置不可访问。栈的基本操作包括入栈(push)和出栈(pop),其中入栈将元素放入栈顶,出栈将栈顶元素移出。

栈在计算机科学和软件开发中有广泛的应用场景,以下是一些常见的使用场景:

1. 表达式求值:栈可以用于解析和计算数学表达式,如中缀表达式转换为后缀表达式,并利用栈进行后缀表达式的求值。

2. 函数调用:在程序执行过程中,每次函数调用时会将当前函数的上下文保存到栈中,包括局部变量、返回地址等。当函数执行完毕后,从栈中取出上一个函数的上下文并恢复执行。

3. 浏览器的历史记录:浏览器通过栈结构来管理用户访问页面的历史记录。每次用户访问一个新页面时,将该页面的 URL 压入栈中;当用户点击返回按钮时,从栈中弹出最近访问的页面 URL,以便回退到上一个页面。

4. 撤销操作:许多应用程序支持撤销操作,其中栈被用于存储每个操作的状态或内容。当用户选择撤销操作时,可以从栈中逐步恢复先前的状态。

5. 地址转跳:在汇编语言和操作系统设计中,栈被用于存储函数调用期间的返回地址。这使得函数可以通过将返回地址压入栈中并使用跳转指令来返回到调用者。

6. 括号匹配:栈可以用于检查表达式中的括号是否匹配。遍历表达式,当遇到左括号时将其压入栈中,当遇到右括号时,若栈顶元素为匹配的左括号,则将栈顶元素弹出,否则说明括号不匹配。

总之,栈是一个非常有用的数据结构,在许多算法和程序设计的场景中都发挥着重要作用,它提供了一种便捷的方式来实现后进先出的操作。

python源码实现

以下是一个使用栈完成表达式计算的示例代码:

class Stack:
    def __init__(self):
        self.stack = []

    def is_empty(self):
        return len(self.stack) == 0

    def push(self, item):
        self.stack.append(item)

    def pop(self):
        if not self.is_empty():
            return self.stack.pop()
        else:
            raise IndexError("Stack is empty")

    def top(self):
        if not self.is_empty():
            return self.stack[-1]
        else:
            raise IndexError("Stack is empty")

def calculate_expression(expression):
    # 定义操作符优先级
    priority = {'+': 1, '-': 1, '*': 2, '/': 2}

    def apply_operator(operator_stack, operand_stack):
        operator = operator_stack.pop()
        operand2 = operand_stack.pop()
        operand1 = operand_stack.pop()

        if operator == '+':
            result = operand1 + operand2
        elif operator == '-':
            result = operand1 - operand2
        elif operator == '*':
            result = operand1 * operand2
        elif operator == '/':
            result = operand1 / operand2
        else:
            raise ValueError("Invalid operator")

        operand_stack.push(result)

    def evaluate(expression):
        operator_stack = Stack()
        operand_stack = Stack()

        for char in expression:
            if char.isdigit():
                operand_stack.push(int(char))
            elif char in priority:
                while (not operator_stack.is_empty() and
                       priority[char] <= priority[operator_stack.top()]):
                    apply_operator(operator_stack, operand_stack)
                operator_stack.push(char)
            elif char == '(':
                operator_stack.push(char)
            elif char == ')':
                while (not operator_stack.is_empty() and
                       operator_stack.top() != '('):
                    apply_operator(operator_stack, operand_stack)
                if operator_stack.is_empty():
                    raise ValueError("Invalid expression")
                operator_stack.pop()

        while not operator_stack.is_empty():
            apply_operator(operator_stack, operand_stack)

        return operand_stack.top()

    return evaluate(expression)

# 测试表达式计算
expression = "(5*10+2-7+5)/10+5"
result = calculate_expression(expression)
print(f"Expression: {expression}")
print(f"Result: {result}")

运行以上代码,将会输出以下结果:

Expression: (5*10+2-7+5)/10+5
Result: 8.5

这段代码使用栈来模拟了表达式的计算过程。首先遍历表达式中的字符,如果是数字,则直接将其放入操作数栈;如果是操作符,则与操作符栈顶的操作符进行比较优先级,如果当前操作符的优先级小于等于栈顶操作符的优先级,则执行栈顶操作符与操作数的计算,并将结果放回操作数栈,直到优先级满足要求。遇到括号时,需要特殊处理。最后,当表达式遍历完毕后,计算剩余的操作符和操作数得到最终结果。

Java源码实现

import java.util.Stack;

public class ExpressionCalculator {
    public static double calculateExpression(String expression) {
        Stack<Double> operandStack = new Stack<>();
        Stack<Character> operatorStack = new Stack<>();

        for (int i = 0; i < expression.length(); i++) {
            char ch = expression.charAt(i);

            if (ch == ' ') {
                continue; // 跳过空格
            }

            if (Character.isDigit(ch)) {
                StringBuilder num = new StringBuilder();
                while (i < expression.length() && (Character.isDigit(expression.charAt(i)) || expression.charAt(i) == '.')) {
                    num.append(expression.charAt(i++));
                }
                operandStack.push(Double.parseDouble(num.toString()));
                i--; // 回退一位,因为在for循环中会自增
            } else if (ch == '(') {
                operatorStack.push(ch);
            } else if (ch == ')') {
                while (operatorStack.peek() != '(') {
                    performOperation(operandStack, operatorStack);
                }
                operatorStack.pop(); // 弹出左括号
            } else if (isOperator(ch)) {
                while (!operatorStack.isEmpty() && hasHigherPrecedence(ch, operatorStack.peek())) {
                    performOperation(operandStack, operatorStack);
                }
                operatorStack.push(ch);
            }
        }

        while (!operatorStack.isEmpty()) {
            performOperation(operandStack, operatorStack);
        }

        return operandStack.pop();
    }

    private static boolean isOperator(char ch) {
        return ch == '+' || ch == '-' || ch == '*' || ch == '/';
    }

    private static boolean hasHigherPrecedence(char op1, char op2) {
        if ((op1 == '*' || op1 == '/') && (op2 == '+' || op2 == '-')) {
            return true;
        }
        return false;
    }

    private static void performOperation(Stack<Double> operandStack, Stack<Character> operatorStack) {
        double num2 = operandStack.pop();
        double num1 = operandStack.pop();
        char operator = operatorStack.pop();

        double result = 0;
        switch (operator) {
            case '+':
                result = num1 + num2;
                break;
            case '-':
                result = num1 - num2;
                break;
            case '*':
                result = num1 * num2;
                break;
            case '/':
                result = num1 / num2;
                break;
        }

        operandStack.push(result);
    }

    public static void main(String[] args) {
        String expression = "(5 * 10 + 2 - 7 + 5) / 10 + 5";
        double result = calculateExpression(expression);
        System.out.println("Result: " + result);
    }
}

具体实现过程如下:

  1. 定义两个栈,一个用于存储操作数(operandStack),另一个用于存储运算符(operatorStack)。

  2. 遍历输入的表达式字符串中的每个字符,根据字符的不同类型执行不同的操作:

    • 如果是数字,将其转换为整数并压入操作数栈中;

    • 如果是左括号,将其压入运算符栈中;

    • 如果是右括号,从运算符栈中弹出所有左括号,直到遇到左括号为止,然后对操作数栈中的元素进行计算,并将结果压入操作数栈中;

    • 如果是运算符,从运算符栈中弹出一个运算符,如果该运算符的优先级高于当前运算符,则先对操作数栈中的元素进行计算,然后再进行当前运算符的计算;否则直接进行当前运算符的计算。最后将计算结果压入操作数栈中。

  3. 当运算符栈为空时,说明已经完成了所有的计算,此时从操作数栈中取出最后一个元素作为最终的结果。

  4. 在主函数中调用calculateExpression方法,传入一个表达式字符串作为参数,并输出计算结果。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/647249.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[数字图像处理]第五章 图像复原与重建

文章目录 第五章 图像复原与重建5.1图像退化复原过程的模型图像退化图像复原图像复原与图像增强图像退化的数学模型为什么采用线性位移不变系统模型来描述图像退化过程 5.2 噪声模型x5.2.1 噪声的空间和频率特性5.2.2 一些重要的噪声概率密度函数高斯噪声实验&#xff1a;采用高…

【微服务架构设计和实现】4.1 微服务架构概述和设计原则

往期回顾&#xff1a; 第一章&#xff1a;【云原生概念和技术】 第二章&#xff1a;【容器化应用程序设计和开发】 第三章&#xff1a;【基于容器的部署、管理和扩展】 4.1 微服务架构概述和设计原则 4.1 微服务架构概述和设计原则4.1.1 微服务架构的优点4.1.2 微服务架构遵…

在 ArcGIS Pro 中使用 H3 创建蜂窝六边形

在 ArcGIS Pro 中使用 H3 创建蜂窝六边形https://mp.weixin.qq.com/s/tGk7AT2jAcvsmNyp2bRvig 之前看了个有意思的ArcGIS博客&#xff1a;H3六边形&#xff0c;当然了这也不是个新鲜东西了。原文&#xff1a; https://www.esri.com/arcgis-blog/products/arcgis-pro/analytic…

为什么要学GIS开发

什么是地理信息系统技术&#xff1f; GIS技术使用专门的计算机系统来获取地理数据并将其集成到智能“超级”地图中。然后&#xff0c;这些数据可用于创建无穷无尽的“假设”场景&#xff0c;为以下应用程序提供强大的工具&#xff1a; 制图&#xff08;地图制作&#xff09;应…

【阅读随笔】Rewrite-Based Decomposition of Signal Temporal Logic Specifications

文章目录 Overview1 IntroLTL任务分解STL任务分解本文工作 Background and Problem DefinitionSTLAgent假设与问题方法 An STL Rewriting SystemRewriting SystemFormula Rewrite DAG Decomposing STL智能体编队任务分解最优分解 Exploring the Formula Rewrite DAGExperiments…

soci在windows下vs2010编译

需要下载 的资源 mysql connector c 因为其使用的的是mysql connector c的api&#xff0c;需要下载https://downloads.mysql.com/archives/c-c/ 分别对应32位和64位的 soci 4.0 从github上下载4.03分支 https://github.com/SOCI/soci/tree/v4.0.3 cmake 需要下载3.25版…

Java多线程快速入门

文章目录 Java多线程快速入门1、认识多线程2、多线程的实现2.1 继承Thread类2.2 实现Runnable接口2.3 利用Callable和Futrue接口2.4 三种方式的比较 3、Thread类常用API3.1 守护线程3.2 礼让线程3.3 插入线程3.4 线程的生命周期 5、线程安全问题5.1 synchronized5.2 Lock 6、等…

wsl安装ubuntu并设置gnome图形界面详细步骤(win11+ubuntu18)

0.前言 wsl确实是个好东西&#xff0c;不过之前配了好几次都没有成功&#xff0c;因为wsl本身确实是有bug。当时配的时候查到GitHub上的一个issue还没被修好。现在重新配一下。 我的环境是Windows11家庭版。区别于win10&#xff0c;win11安装完默认就是wsl2。 1.下载 首先打…

Linux之管理联网

目录 Linux之管理联网 rhel8与7的区别 NetworkManager 定义 NM能管理各种网络 使用方法 使用NM的原因 nmcli使用方法 nmcli的两个常用命令 nmcli connection 定义 两种状态 nmcli device 定义 四种状态 nmcli常用命令 查看ip&#xff08;类似于ifconfig、ip addr&a…

每周练习学习(一)1.1--nc的使用与系统命令执行

1.test_your_nc ----nc的使用与系统命令执行1 平台&#xff1a;buuctf 之前在攻防开学来考核的时候&#xff0c;遇到过一个nc的题&#xff0c;但自己完全不知道nc是什么意思&#xff0c;所以现在为了增强一点自己的知识面&#xff08;说的好听&#xff0c;也就是为了快期末…

4.8 Socket介绍 4.9字节序 4.10字节序转换函数

4.8 Socket介绍 所谓 socket&#xff08;套接字&#xff09;&#xff0c;就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。一个套接字就是网络上进程通信的一端&#xff0c;提供了应用层进程利用网络协议交换数据的机制。从所处的地位来讲&#xff0c;套接字上…

使用EasyCode自定义模板,自动生成代码

首先创建spring boot项目&#xff0c;导入相关依赖是必须的#### 导入依赖&#xff1a; pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001…

设计模式(十八):行为型之观察者模式

设计模式系列文章 设计模式(一)&#xff1a;创建型之单例模式 设计模式(二、三)&#xff1a;创建型之工厂方法和抽象工厂模式 设计模式(四)&#xff1a;创建型之原型模式 设计模式(五)&#xff1a;创建型之建造者模式 设计模式(六)&#xff1a;结构型之代理模式 设计模式…

【RabbitMQ教程】第六章 —— RabbitMQ - 延迟队列

&#x1f4a7; 【 R a b b i t M Q 教程】第六章—— R a b b i t M Q − 延迟队列 \color{#FF1493}{【RabbitMQ教程】第六章 —— RabbitMQ - 延迟队列} 【RabbitMQ教程】第六章——RabbitMQ−延迟队列&#x1f4a7; &#x1f337; 仰望天空&#xff0c;妳我亦是行人…

数据提取概述

数据提取概述 一、响应内容的分类 在发送请求获取响应之后&#xff0c;可能存在多种不同类型的响应内容&#xff1b;而且很多时候&#xff0c;我们只需要响应内容中的一部分数据 结构化的响应内容 json字符串 可以使用re、json等模块来提取特定数据json字符串的例子如下图 x…

一.《UE5夜鸦》被动技能名字CALL和描述CALL

被动技能名字描述CALL 搜索名字寻找名字库的名字对象 1.搜索我们找名字,肯定是需要用CE搜索名字拉,由于是韩文,我们用翻译器截图获取韩文字符串 2.开始截图获取 3.我们用CE搜索字符串,这里注意是UTF-16勾上,找到了4个完全一样的结果, 我们修改确认哪一个才是真正技能库的名字 4…

[读论文]Referring Camouflaged Object Detection

摘要 In this paper, we consider the problem of referring camouflaged object detection (Ref-COD), a new task that aims to segment specified camouflaged objects based on some form of reference, e.g. , image, text. We first assemble a large-scale dataset, ca…

NLP——Translation 机器翻译

文章目录 为什么翻译任务困难Statistical Machine TranslationAlignment 对齐summary Neural Machine Translation如何训练 Neural MTloss 设定Trainingdecoding at Test TimeExposure BiasExhaustive Search DecodingBeam Search Decoding什么时候解码停止summary Attention M…

Linux 文件 io 的原子性与 O_APPEND 参数

转自&#xff1a;https://www.cnblogs.com/moonwalk/p/15642478.html 1. 文件 io 1.1 open() 系统调用 在进程/线程 struct task ---> struct files_struct 结构体中&#xff0c;添加一项新打开的文件描述符 fd&#xff0c;并指向文件表创建一个新的 struct file 即文件表…

Debezium系列之:为Debezium集群JMX页面增加监控,JMX页面出现异常时发送飞书告警,确保任务能够获取debezium集群指标

Debezium系列之:为Debezium集群JMX页面增加监控,JMX页面出现异常时发送飞书告警,确保任务能够获取debezium集群指标 一、需求背景二、相关技术博客三、监控JMX页面状态四、发送飞书告警五、定时执行脚本六、告警效果展示七、总结和延展一、需求背景 下游任务需要使用Debeziu…