一、效果展示

如图1所示,是简单的四则运算测试效果,第一列为原始表达式,第二列为转换后的后缀表达式,冒号后为结果。表达式支持负数和空格,图中是使用了5组测试数据,测试结果可能不全,如大家发现算法有问题,可留言,谢谢。

图1 四则运算展示

测试代码如下

 void lineedit::CalculateExpression()
{
QString reExp("1 + 2.3 * (23 + 3)");
QString res = change(reExp);//0 1 - 2.3 23 3 + * + QString reExp2("1*(-3)+2*(3+3)");
QString res2 = change(reExp2); QString reExp3("2*-3+-2.1*(3+3)");
repairExpress(reExp3);
QString res3 = change(reExp3); QString reExp4("2*(-3)+-2.1*(3+3)");
repairExpress(reExp4);
QString res4 = change(reExp4); QString reExp5("2*(0-(1.1-3)*3)+-2.1*(3+3)");
repairExpress(reExp5);
QString res5 = change(reExp5); qDebug() << reExp << '\t'<< res << ":" << CalExp(res.split(' ', QString::SkipEmptyParts));
qDebug() << reExp2 << '\t'<< res2 << ":" << CalExp(res2.split(' ', QString::SkipEmptyParts));
qDebug() << reExp3 << '\t'<< res3 << ":" << CalExp(res3.split(' ', QString::SkipEmptyParts));
qDebug() << reExp4 << '\t'<< res4 << ":" << CalExp(res4.split(' ', QString::SkipEmptyParts));
qDebug() << reExp5 << '\t'<< res5 << ":" << CalExp(res5.split(' ', QString::SkipEmptyParts));
}

二、一些小技巧

  在网上找了很多四则运算帖子,讲的都挺不错,思路很清晰,可是很少有拿来直接能用的,并且大多数的都不支持负数运算,既然是四则运算当然需要支持负数运算了,在这里我们只需要使用一点儿小技巧即可。

1、针对负号进行字符串修复 例如:-1*-3+2*(3+3) -> (0-1)*(0-3)+2*(3+3)。

 //针对负号进行字符串修复 例如:-1*-3+2*(3+3) -> (0-1)*(0-3)+2*(3+3)
void repairExpress(QString & express)
{
bool repair = false;
int lpos = -, rpos = -;
QString result;
for(int i = ; i < express.size(); ++i)
{
QChar c = express[i];
if (c == '+' || c == '-' || c == '*' || c == '/')//出现符号时记录
{
if (repair)
{
result.append(')');
lpos = -;
repair = false;
} if (c == '-'&&
(i == || lpos != - && lpos == i - ))
{
result.append('(');
repair = true;
} lpos = i;
} result.append(c);
} express = result;
}

2、为了方便后续我们计算表达式,在中缀表达式转后缀表达式时,我们在数字和负号之间加了一个空格。

 //数字和负号之间插入空格, 方便后续计算时分割
void rettifyExpress(QString & express)
{
if (express.endsWith(' ') == false)
{
express.append(' ');
}
}

三、后缀表达式

中缀表达式:是一个通用的算术或逻辑公式表示方法, 操作符是以中缀形式处于操作数的中间(例:3 + 4),中缀表达式是人们常用的算术表示方法。

后缀表达式:后缀表达式,指的是不包含括号,运算符放在两个运算对象的后面,所有的计算按运算符出现的顺序,严格从左向右进行(不再考虑运算符的优先规则)。

中缀表达式转后缀表达式的方法:

1.遇到操作数:直接输出(添加到后缀表达式中)
2.栈为空时,遇到运算符,直接入栈
3.遇到左括号:将其入栈
4.遇到右括号:执行出栈操作,并将出栈的元素输出,直到弹出栈的是左括号,左括号不输出。
5.遇到其他运算符:加减乘除:弹出所有优先级大于或者等于该运算符的栈顶元素,然后将该运算符入栈
6.最终将栈中的元素依次出栈,输出。

下边我直接给出实现代码

 //中缀表达式转后缀表达式
QString change(const QString & s_mid)
{
QString result;
QStack<QChar> stk; QMap<QChar, int> op;//利用map来实现运算符对应其优先级
op['(']=;
op[')']=;
op['+']=;
op['-']=;
op['*']=;
op['/']=;
auto iter = s_mid.begin();
for(int i = ; i < s_mid.size(); ++i)
{
QChar c = s_mid[i];
if (c == ' ')
{
continue;
}
if (c == '-' &&
(i == || op.contains(s_mid[i-])))//可能为负号
{
result.append('');
}
if(op.contains(c))//判断该元素是否为运算符
{
if(c == ')')//情况2
{
while(stk.top() != '(')
{
rettifyExpress(result);
result.append(stk.top());
stk.pop();
}
stk.pop();
}
else if(stk.empty() || c == '(' || op[c] > op[stk.top()])//情况1、情况3
{
stk.push(c);
}
else if(op[c] <= op[stk.top()])//情况3
{
while(op[c] <= op[stk.top()] && (!stk.empty()))
{
rettifyExpress(result);
result.append(stk.top());
stk.pop();
if(stk.empty()) break;
}
stk.push(c);
} rettifyExpress(result);
}
else
{
result.append(c);
}
} while(stk.empty() == false)//当中缀表达式输出完成,所有元素出栈
{
rettifyExpress(result);
result.append(stk.top());
stk.pop();
} return result;
}

四、表达式计算

通过后缀表达式计算时,我们就不需要考虑优先级了,只需要严格按照从左向右,遇到负号取之前的两个数值进行计算即可。

 //计算表达式值
double CalExp(const QStringList & express)
{
double result;
QStack<QString> stk;
for (int i = ; i < express.size(); ++i)
{
QString item = express[i];
if (item.size() == &&
(item.at() == "+" || item.at() == "-" || item.at() == "*" || item.at() == "/"))
{
double r = stk.pop().toDouble();
double l = stk.pop().toDouble();
switch(item.at().toLatin1())
{
case '+':
result = l + r;break;
case '-':
result = l - r;break;
case '*':
result = l * r;break;
case '/':
result = l / r;break;
} stk.push_back(QString::number(result));
}
else
{
stk.push_back(item);
}
} return result;
}

五、下载链接

  Qt之加减乘除四则运算-支持负数

参考文章:

1、四则运算表达式树 C++模板 支持括号和未知数

2、中缀表达式得到后缀表达式(c++、python实现)

Qt之加减乘除四则运算-支持负数的更多相关文章

  1. Qt国际化(Q_DECLARE_TR_FUNCTIONS() 宏给非Qt类添加翻译支持,以前没见过QTextEncoder和QTextDecoder和QLibraryInfo::location()和QEvent::LanguageChange)

    Internationalization with Qt 应用程序的国际化就是使得程序能在国际间可用而不仅仅是在本国可用的过程. Relevant Qt Classes andAPIs 以下的类支持Q ...

  2. python列表很聪明,支持负数索引

    python列表很聪明,支持负数索引

  3. Qt4学习笔记 (7) 本篇说一下Qt对于脚本的支持, 即QtScript模块.

    本篇说一下Qt对于脚本的支持, 即QtScript模块. Qt支持的脚本基于ECMAScript脚本语言, 这个东西又是javascript, jscript的基础. 所以, 一般只要学过javasc ...

  4. Python基础算法综合:加减乘除四则运算方法

    #!usr/bin/env python# -*- coding:utf-8 -*-#python的算法加减乘除用符号:+,-,*,/来表示#以下全是python2.x写法,3.x以上请在python ...

  5. Qt增加webp格式支持

    Webp 是一种图片文件格式,能在相同质量的情况下比 PNG 文件尺寸小巧. Chrome 应用商店图片已全部转换为 WebP 格式 YY(基于Qt开发)也已经把图片格式换成webp了 http:// ...

  6. Qt入门(9)——Qt中的线程支持

    Qt对线程提供了支持,基本形式有独立于平台的线程类.线程安全方式的事件传递和一个全局Qt库互斥量允许你可以从不同的线程调用Qt方法.警告:所有的GUI类(比如,QWidget和它的子类),操作系统核心 ...

  7. java实现超大整数加减乘除四则运算

    原理: 用数组存储数字,按照计算法则进行运算. 代码: package com.hdwang; import java.util.regex.Matcher; import java.util.reg ...

  8. poj 1348 Computing (四个数的加减乘除四则运算)

    http://poj.org/problem?id=1348 Computing Time Limit: 1000MS   Memory Limit: 10000K Total Submissions ...

  9. 用Java位运算实现加减乘除四则运算

    转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6412875.html 感谢博客:http://blog.csdn.net/itismelzp/article/ ...

随机推荐

  1. Java开源生鲜电商平台-系统简介

    Java开源生鲜电商平台-系统简介 1.生鲜电商平台的价值与定位. 生鲜电商平台是一家致力于打造全国餐饮行业智能化.便利化.平台化与透明化服务的创新型移动互联网平台,连接买家与卖家之间的一个平台 看以 ...

  2. Yii2快速总结

    1.项目目录 后面的总结都是基于这个项目目录,注意:这个Yii2框架的basic版本原始的目录结构,未作任何更改. 2.新建控制器以及视图 controllers这个目录下的SiteControlle ...

  3. Android之淘宝商品列表长按遮罩效果

    先来看看淘宝.唯品会长按商品的效果,以及简单Demo的效果:        首先分析一下场景: 长按条目时,弹出遮罩的效果遮挡在原来的条目布局上: 页面滑动或点击其他的条目,上一个正在遮罩的条目遮罩消 ...

  4. Java面向对象(一、封装)

    Java 封装 封装的概念 在面向对象程式设计方法中,封装(英语:Encapsulation)是指一种将抽象性函式接口的实现细节部份包装.隐藏起来的方法. 封装可以被认为是一个保护屏障,防止该类的代码 ...

  5. Maven Scope 依赖范围

    Maven依赖范围就是用来控制依赖与这三种classpath(编译classpath.测试classpath.运行classpath)的关系,Maven有以下几种依赖范围: ·compile:编译依赖 ...

  6. Oracle12c中PL/SQL(DBMS_SQL)新特性之隐式语句结果(DBMS_SQL.RETURN_RESULT and DBMS_SQL.GET_NEXT_RESULT)

    隐式数据结果特性将能简化从其他数据库到Oracle12c存储过程迁移.1. 背景T-SQL中允许查询结果的隐式返回.例如:下面T-SQL存储过程隐式返回查询结果.CREATE PROCEDURE Ge ...

  7. PAT1032: Sharing (25)

    1032. Sharing (25) 时间限制 100 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue To store Engl ...

  8. TCP入门与实例讲解

    内容简介 TCP是TCP/IP协议栈的核心组成之一,对开发者来说,学习.掌握TCP非常重要. 本文主要内容包括:什么是TCP,为什么要学习TCP,TCP协议格式,通过实例讲解TCP的生命周期(建立连接 ...

  9. 关于for循环里面异步操作的问题

    首先来看一个比较简单的问题,我们想实现的就是每隔1s输出0-4的值,就是这么简单,看下错误写法: function test() { for (var i = 0; i < 5; ++i) { ...

  10. web优化(一)

    今天读完了<高性能网站建设进阶指南>,记得博客园的某位前辈说,关于前端方面的书,带指南两个字的一般都是比较牛逼的,上一本看到的好书是<javascript权威指南>是淘宝前段团 ...