Qt 第9课、计算器中缀转后缀算法

news2024/9/26 3:25:46

计算器核心算法:

1、将中缀表达式进行数字运算符的分离
2、将中缀表达式转换成后缀表达式
3、通过后缀表达式计算最后的结果
在这里插入图片描述


二、计算器中缀转后缀算法

计算器中缀转后缀算法的意义在于把中缀表达式转换成后缀表达式,能够更好地计算

  • 算法的基本思路
    1、如果是isNumber,直接进输出队列
    2、如果是isOperator
    如果一个运算符优先级 <= 前一个运算符优先级,则这个前面那个运算符进输出队列
    其余的全部进栈
    3、如果是左括号,进栈
    4、如果是右括号,直到栈顶为左括号才不用把栈里的进输出队列,
    把栈顶元素pop()
    5、其余的报错
    如果栈里面不为空,直接全部进队列
bool QCalculatorDec::transform(QQueue<QString>& exp, QQueue<QString>& output)
{
    bool ret = match(exp);
    output.clear();
    QStack<QString> stack;

    while(ret && !exp.isEmpty())
    {
        QString str = exp.dequeue();

        if(isNumber(str))
        {
            output.enqueue(str);
        }
        else if(isOperator(str))
        {
            while(!stack.isEmpty() && priority(str) <= priority(stack.top()))
            {
                output.enqueue(stack.pop());
            }
            stack.push(str);
        }
        else if(isLeft(str))
        {
            stack.push(str);
        }
        else if(isRight(str))
        {
            while(!stack.isEmpty() && !isLeft(stack.top()))
            {
                output.enqueue(stack.pop());
            }
            stack.pop();
        }
        else
        {
            ret = false;
        }
    }
    while(!stack.isEmpty())
    {
        output.enqueue(stack.pop());
    }
    if(!ret)
    {
        output.clear();
    }
    return ret;
}

4、计算器后缀表达式计算算法

QString QCalculatorDec::calculate(QString l, QString op, QString r)
{
    QString ret = "Error";
    if(isNumber(l) && isNumber(r))
    {
        double lp = l.toDouble();
        double rp = r.toDouble();

        if(op == "+")
        {
            ret.sprintf("%f", lp + rp);
        }
        else if(op == "-")
        {
            ret.sprintf("%f", lp - rp);
        }
        else if(op == "*")
        {
            ret.sprintf("%f", lp * rp);
        }
        else if(op == "/")
        {
            double delta = 0.0000000001;
            if(rp >= -delta && rp <= delta)
            {
                ret = "Error";
            }
            else
            {
                ret.sprintf("%f", lp / rp);
            }
        }
        else
        {
            ret = "Error";
        }
    }
    return ret;
}

QString QCalculatorDec::calculate(QQueue<QString>& exp)
{
    QString ret = "Error";
    QStack<QString> stack;
    while(!exp.isEmpty())
    {
        QString str = exp.dequeue();
        if(isNumber(str))
        {
            stack.push(str);
        }
        else if(isOperator(str))
        {
            QString rp = !stack.isEmpty() ? stack.pop() : "";
            QString lp = !stack.isEmpty() ? stack.pop() : "";

            QString result = calculate(lp, str, rp);

            if(result != "Error")
            {
                stack.push(result);
            }
            else
            {
                break;
            }
        }
    }
    if(exp.isEmpty() && stack.size() == 1 && isNumber(stack.top()))
    {
        ret = stack.pop();
    }
    return ret;
}

5、通过一个函数包含所有计算器的核心算法

bool QCalculatorDec::expression(const QString& exp)
{
    bool ret = false;
    QQueue<QString> spExp = split(exp);
    QQueue<QString> postExp;
    m_exp = exp;

    if(transform(spExp, postExp))
    {
        m_result = calculate(postExp);
        ret = (m_result != "Error");
    }
    else
    {
        m_result = "Error";
    }
    return ret;
}
QString QCalculatorDec::result()
{
    return m_result;
}

计算器算法实现的源代码:

QCalculatorDec.h

#ifndef QCALCULATORDEC_H
#define QCALCULATORDEC_H
#include <QQueue>
#include <QString>
#include <QStack>

#include "ICalculator.h"
class QCalculatorDec
{
protected:
    QString m_exp;
    QString m_result;

    bool isDigitOrDot(QChar c);
    bool isSign(QChar c);
    bool isSymbol(QChar c);

    bool isOperator(QString s);
    bool isLeft(QString s);
    bool isRight(QString s);
    bool isNumber(QString s);
    int priority(QString s);

    QQueue<QString> split(const QString& exp);
    bool match(QQueue<QString>& exp);
    bool transform(QQueue<QString>& exp, QQueue<QString>& output);
    QString calculate(QString l, QString op, QString r);
    QString calculate(QQueue<QString>& exp);
public:
    QCalculatorDec();
    bool expression(const QString& exp);
    QString expression();
    QString result();
    ~QCalculatorDec();
};

#endif // QCALCULATORDEC_H

QCalculatorDec.cpp

#include "QCalculatorDec.h"
#include <QDebug>
QCalculatorDec::QCalculatorDec()
{
    m_exp = "";
    m_result = "";
}

bool QCalculatorDec::isDigitOrDot(QChar c)
{
    return ((c >= '0')&&(c <= '9'))||(c == '.');
}

bool QCalculatorDec::isSign(QChar c)
{
    return (c == '+')||(c == '-');
}

bool QCalculatorDec::isSymbol(QChar c)
{
    return isOperator(c)||(c == '(')||(c == ')');
}

bool QCalculatorDec::isOperator(QString s)
{
    return (s == "+")||(s == "-")||(s == "*")||(s == "/");
}

bool QCalculatorDec::isLeft(QString s)
{
    return (s == "(");
}

bool QCalculatorDec::isRight(QString s)
{
    return (s == ")");
}

bool QCalculatorDec::isNumber(QString s)
{
    bool ret = false;
    s.toDouble(&ret);
    return ret;
}

int QCalculatorDec::priority(QString s)
{
    int ret = 0;
    if(s == "+"||s == "-")
    {
        ret = 1;
    }
    else if(s == "*"||s == "/")
    {
        ret = 2;
    }
    return ret;
}

QQueue<QString> QCalculatorDec::split(const QString& exp)
{
    QQueue<QString> ret;
    QString num;
    QString pre;

    for(int i = 0; i < exp.length(); i++)
    {
        if(isDigitOrDot(exp[i]))
        {
            num += exp[i];
            pre = exp[i];
        }
        else if(isSymbol(exp[i]))
        {
            if(!num.isEmpty())
            {
                ret.enqueue(num);
                num.clear();
            }
            if(isSign(exp[i])&&(pre == "" || isLeft(pre) || isOperator(pre)))
            {
                num += exp[i];
            }
            else
            {
                ret.enqueue(exp[i]);
            }
            pre = exp[i];
        }
    }
    if(!num.isEmpty())
    {
        ret.enqueue(num);
    }
    return ret;
}

bool QCalculatorDec::match(QQueue<QString>& exp)
{
    bool ret = true;
    QStack<QString> stack;
    for(int i = 0; i < exp.length(); i++)
    {
        if(isLeft(exp[i]))
        {
            stack.push(exp[i]);
        }
        else if(isRight(exp[i]))
        {
            if(isLeft(stack.top()))
            {
                stack.pop();
            }
            else
            {
                ret = false;
            }
        }
    }
    if(!stack.isEmpty())
    {
        ret = false;
    }

    return ret;
}

bool QCalculatorDec::transform(QQueue<QString>& exp, QQueue<QString>& output)
{
    bool ret = match(exp);
    output.clear();
    QStack<QString> stack;

    while(ret && !exp.isEmpty())
    {
        QString str = exp.dequeue();

        if(isNumber(str))
        {
            output.enqueue(str);
        }
        else if(isOperator(str))
        {
            while(!stack.isEmpty() && priority(str) <= priority(stack.top()))
            {
                output.enqueue(stack.pop());
            }
            stack.push(str);
        }
        else if(isLeft(str))
        {
            stack.push(str);
        }
        else if(isRight(str))
        {
            while(!stack.isEmpty() && !isLeft(stack.top()))
            {
                output.enqueue(stack.pop());
            }
            stack.pop();
        }
        else
        {
            ret = false;
        }
    }
    while(!stack.isEmpty())
    {
        output.enqueue(stack.pop());
    }
    if(!ret)
    {
        output.clear();
    }
    return ret;
}

QString QCalculatorDec::calculate(QString l, QString op, QString r)
{
    QString ret = "Error";
    if(isNumber(l) && isNumber(r))
    {
        double lp = l.toDouble();
        double rp = r.toDouble();

        if(op == "+")
        {
            ret.sprintf("%f", lp + rp);
        }
        else if(op == "-")
        {
            ret.sprintf("%f", lp - rp);
        }
        else if(op == "*")
        {
            ret.sprintf("%f", lp * rp);
        }
        else if(op == "/")
        {
            double delta = 0.0000000001;
            if(rp >= -delta && rp <= delta)
            {
                ret = "Error";
            }
            else
            {
                ret.sprintf("%f", lp / rp);
            }
        }
        else
        {
            ret = "Error";
        }
    }
    return ret;
}

QString QCalculatorDec::calculate(QQueue<QString>& exp)
{
    QString ret = "Error";
    QStack<QString> stack;
    while(!exp.isEmpty())
    {
        QString str = exp.dequeue();
        if(isNumber(str))
        {
            stack.push(str);
        }
        else if(isOperator(str))
        {
            QString rp = !stack.isEmpty() ? stack.pop() : "";
            QString lp = !stack.isEmpty() ? stack.pop() : "";

            QString result = calculate(lp, str, rp);

            if(result != "Error")
            {
                stack.push(result);
            }
            else
            {
                break;
            }
        }
    }
    if(exp.isEmpty() && stack.size() == 1 && isNumber(stack.top()))
    {
        ret = stack.pop();
    }
    return ret;
}

bool QCalculatorDec::expression(const QString& exp)
{
    bool ret = false;
    QQueue<QString> spExp = split(exp);
    QQueue<QString> postExp;
    m_exp = exp;

    if(transform(spExp, postExp))
    {
        m_result = calculate(postExp);
        ret = (m_result != "Error");
    }
    else
    {
        m_result = "Error";
    }
    return ret;
}

QString QCalculatorDec::expression()
{
    return  m_exp;
}

QString QCalculatorDec::result()
{
    return m_result;
}

QCalculatorDec::~QCalculatorDec()
{

}

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

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

相关文章

【RabbitMQ笔记08】消息队列RabbitMQ之防止消息丢失的三种方式(生产者消息确认、消费者消息确认、消息持久化)

这篇文章&#xff0c;主要介绍消息队列RabbitMQ之防止消息丢失的三种方式&#xff08;生产者消息确认、消费者消息确认、消息持久化&#xff09;。 目录 一、防止消息丢失 1.1、消息确认机制&#xff08;生产者&#xff09; &#xff08;1&#xff09;生产者丢失消息 &…

字节跳动软件测试岗4轮面经(已拿34K+ offer)...

没有绝对的天才&#xff0c;只有持续不断的付出。对于我们每一个平凡人来说&#xff0c;改变命运只能依靠努力幸运&#xff0c;但如果你不够幸运&#xff0c;那就只能拉高努力的占比。 2021年10月&#xff0c;我有幸成为了字节跳动的一名测试工程师&#xff0c;从外包辞职了历…

一文读懂自动驾驶运行设计域ODD

/ 导读 /在自动驾驶技术发展如此迅速的今天&#xff0c;很多量产车上已经配备了多种的辅助驾驶功能&#xff0c;例如自适应巡航ACC、紧急制动AEB、车道居中保持LKA等等&#xff0c;很多的车主也都体验到了技术带给驾驶的改变。另一方面&#xff0c;由于现在的自动驾驶技术还处于…

量化选股——基于动量因子的行业风格轮动策略(第2部分—策略回测)

文章目录1. 交易策略2. Backtrader回测程序3. 回测效果3.1 2020年1月1日 - 2021年1月1日3.2 2021年1月1日 — 2022年1月1日3.3 2022年1月1日 — 2023年1月1日动量因子的概述与测算&#xff0c;阿隆指标测算请参考&#xff1a;https://blog.csdn.net/weixin_35757704/article/de…

react源码解析1.开篇介绍和面试题

怎样学习react源码 作为前端最常用的js库之一&#xff0c;熟悉react源码成了高级或资深前端工程师必备的能力&#xff0c;如果你不想停留在api的使用层面或者想在前端技能的深度上有所突破&#xff0c;那熟悉react源码将是你进步的很好的方式。 react的纯粹体现在它的api上&a…

【神经网络】LSTM

1.什么是LSTM 长短期记忆&#xff08;Long short-term memory, LSTM&#xff09;是一种特殊的RNN&#xff0c;主要是为了解决长序列训练过程中的梯度消失和梯度爆炸问题。简单来说&#xff0c;相比普通的RNN&#xff0c;LSTM能够在更长的序列中有更好的表现。 LSTM区别于RNN地方…

Java查漏补缺(09)异常概述、Java异常体系、常见的错误和异常、异常的处理、手动抛出异常对象:throw、自定义异常

Java查漏补缺&#xff08;09&#xff09;异常概述、Java异常体系、常见的错误和异常、异常的处理、手动抛出异常对象&#xff1a;throw、自定义异常本章专题与脉络1. 异常概述1.1 什么是生活的异常1.2 什么是程序的异常1.3 异常的抛出机制1.4 如何对待异常2. Java异常体系2.1 T…

【JAVA】xxl-job服务搭建

xxl-job服务搭建 1.下载xxl-job项目 https://github.com/xuxueli/xxl-job 2.数据库表创建 3.修改配置 注意&#xff1a;这是两个项目&#xff0c;一个是xxl-job前台&#xff0c;一个是xxl-job执行器&#xff0c;找到这两个项目得配置文件&#xff0c;修改配置。 配置文件地址…

day54【代码随想录】二刷数组

文章目录前言一、二分查找&#xff08;力扣724&#xff09;二、移除元素&#xff08;力扣27&#xff09;【双指针】三、有序数组的平方&#xff08;力扣977&#xff09;【双指针】四、合并两个有序数组&#xff08;力扣88&#xff09;五、长度最小的子数组&#xff08;力扣209&…

前端学习第二阶段-第3章 Flex 伸缩布局

3-1 移动端基础知识 01-移动端基础 02-视口 03-meta视口标签 04-物理像素与物理像素比 05-二倍图 06-背景缩放background-size 07-背景二倍图以及多倍图切图 08-移动端开发选择 09-移动端技术解决方案 10-移动端特殊样式 11-移动端技术选型 12-流式布局 3-2 移动端电商首页制作…

Python基础—while循环

(1)while循环&#xff1a; 语法格式&#xff1a; while 条件&#xff1a;   执行语句1……   执行语句2…… 适用条件&#xff1a;无限循环 死循环 while True:print(条件是真的&#xff01;)代码实例&#xff1a; i 0 # 创建一个计数的变量 while i < 5: # Truepr…

感知趋势,洞察发展:2023(第十届)趋势与预测大会成功举办

2023年2月23日&#xff0c;运联年会&#xff1a;2023&#xff08;第十届&#xff09;趋势与预测大会在深圳机场凯悦酒店成功闭幕。自2014年开始&#xff0c;“运联年会&#xff1a;趋势与预测”已经连续举办九届。这场大会&#xff0c;既是一次行业性的“年终总结”&#xff0c…

【Java开发】JUC基础 01:进程、线程、多线程

1 进程与线程1.1 进程开发写的代码称为程序&#xff0c;那么我们将程序运行起来&#xff0c;我们称之为进程&#xff1b;进程就是申请一块内存空间&#xff0c;将数据放到内存空间中去&#xff0c;是系统进行资源分配和调度的基本单位。&#x1f4cc; 程序与进程的区别程序是数…

QML Item

在QML中所有的可视项目都继承自Item&#xff0c;虽然Item本身没有可视化的外观&#xff0c;但它定义了可视化项目的所有属性。 Item可以作为容器使用&#xff1a; Item{Rectangle{id:retc}Rectangle{id:retc1}Rectangle{id:retc2}Rectangle{id:retc3}} item拥有children属性…

MyBatis学习笔记(七) —— 特殊SQL的执行

7、特殊SQL的执行 7.1、模糊查询 模糊查询的三种方式&#xff1a; 方式1&#xff1a;select * from t_user where username like ‘%${mohu}%’ 方式2&#xff1a;select * from t_user where username like concat(‘%’,#{mohu},‘%’) 方式3&#xff1a;select * from t_u…

DolphinScheduler跨版本升级1.3.8至3.0.1

DolphinScheduler跨版本升级1.3.8至3.0.1Refer背景基础环境依赖版本升级修改pom.xml问题解决MYSQL升级1.文件替换2.修改表结构t_ds_process_definitiont_ds_alertt_ds_process_instance3.时间参数修改4.数据库升级DOLPHIN安装zookeeper集群创建用户dolphinscheduler_env.shinst…

指针变量作为函数参数详解,形参和实参之间的值传递如何传递?如何改变指针变量所指向的变量?

函数的参数不仅可以是整型&#xff0c;浮点型&#xff0c;字符型等数据&#xff0c;还可以是指针类型&#xff1b;它的作用是将一个变量的地址传送到另一个函数中。 关于地址&#xff0c;指针&#xff0c;指针变量可以参考我的上一篇文章&#xff1a; 地址&#xff0c;指针&…

线程的基本方法

线程等待&#xff1a;wait方法 调用wait方法的线程会进入WAITING状态&#xff0c;只有等到其他线程的通知或程序被中断才会返回。调用wait方法后会释放对象的锁&#xff0c;因此 wait方法一般被用于同步方法或同步代码块中 。 线程睡眠&#xff1a;sleep方法 调用sleep方法会导…

Spring Boot 版本升级2.2.11.RELEASE至2.7.4

2.2.11.RELEASE > 2.7.4项目更新spring-boot-starter-parent 主依赖&#xff0c;导致项目跑不起了日志也没有输出有用信息&#xff0c;自己查看源码调试启动入口打断点&#xff0c;一步步进入方法定位项目停止代码我的项目执行到SpringApplication.class 的152行代码会停止项…

华为HCIE学习之Openstack Glance组件(glance对接swift)

文章目录一、Glance的结构二、服务部署流程三、将glance存储在swift中1、默认使用swift来存储2、指定可以存在swift中3、swift版本4、keystone的endpoint地址&#xff08;当glance去找swift时通过keystone去找&#xff09;5、租户名:用户名&#xff0c;用户必须拥有admin角色6、…