Qt之加减乘除四则运算-支持负数
一、效果展示
如图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之加减乘除四则运算-支持负数的更多相关文章
- Qt国际化(Q_DECLARE_TR_FUNCTIONS() 宏给非Qt类添加翻译支持,以前没见过QTextEncoder和QTextDecoder和QLibraryInfo::location()和QEvent::LanguageChange)
Internationalization with Qt 应用程序的国际化就是使得程序能在国际间可用而不仅仅是在本国可用的过程. Relevant Qt Classes andAPIs 以下的类支持Q ...
- python列表很聪明,支持负数索引
python列表很聪明,支持负数索引
- Qt4学习笔记 (7) 本篇说一下Qt对于脚本的支持, 即QtScript模块.
本篇说一下Qt对于脚本的支持, 即QtScript模块. Qt支持的脚本基于ECMAScript脚本语言, 这个东西又是javascript, jscript的基础. 所以, 一般只要学过javasc ...
- Python基础算法综合:加减乘除四则运算方法
#!usr/bin/env python# -*- coding:utf-8 -*-#python的算法加减乘除用符号:+,-,*,/来表示#以下全是python2.x写法,3.x以上请在python ...
- Qt增加webp格式支持
Webp 是一种图片文件格式,能在相同质量的情况下比 PNG 文件尺寸小巧. Chrome 应用商店图片已全部转换为 WebP 格式 YY(基于Qt开发)也已经把图片格式换成webp了 http:// ...
- Qt入门(9)——Qt中的线程支持
Qt对线程提供了支持,基本形式有独立于平台的线程类.线程安全方式的事件传递和一个全局Qt库互斥量允许你可以从不同的线程调用Qt方法.警告:所有的GUI类(比如,QWidget和它的子类),操作系统核心 ...
- java实现超大整数加减乘除四则运算
原理: 用数组存储数字,按照计算法则进行运算. 代码: package com.hdwang; import java.util.regex.Matcher; import java.util.reg ...
- poj 1348 Computing (四个数的加减乘除四则运算)
http://poj.org/problem?id=1348 Computing Time Limit: 1000MS Memory Limit: 10000K Total Submissions ...
- 用Java位运算实现加减乘除四则运算
转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6412875.html 感谢博客:http://blog.csdn.net/itismelzp/article/ ...
随机推荐
- Solr(三)向solr-5.5.4中添加数据
Solr添加数据 一 首先在创建好的CORE中添加自己需要的Field(可以理解为表的字段) 1 切换到配置Field的文件目录,编辑配置Field的文件 managed-schema cd /usr ...
- MySQL数据库主从分离的配置方法
1.介绍 MySQL数据库设置读写分离,可以使对数据库的写操作和读操作在不同服务器上执行,提高并发量和响应速度.现在的网站一般大点的,都采用有数据库主从分离.读写分离,既起到备份作用也可以减轻数据库的 ...
- 简单记录numpy库的某些基本功能
这里介绍python的一个库,numpy库,这个库是机器学习,数据分析最经常用到的库之一,也是利用python做数据必须用到的一个库,入门机器学习学的第一个python库就是它了. 先对其导入到pyt ...
- 1 Numpy-科学计算
在Python中,使用list可以保存一组值,可以作为数组使用,但是比较浪费内存和时间.类似的array模块,不支持多维,也没有各种函数运算,因此也极其不方便. 为解决这一问题,Python提供了Nu ...
- 设计模式的征途—17.模板方法(Template Method)模式
在现实生活中,很多事情都需要经过几个步骤才能完成,例如请客吃饭,无论吃什么,一般都包含:点单.吃东西.买单等几个步骤,通常情况下这几个步骤的次序是:点单=>吃东西=>买单.在这3个步骤中, ...
- 洛谷 P1691 解题报告
P1691 有重复元素的排列问题 题目描述 设\(R={r_1,r_2,--,r_n}\)是要进行排列的\(n\)个元素.其中元素\(r_1,r_2,--,r_n\)可能相同.使设计一个算法,列出\( ...
- Netflix性能监控工具Vector
简介: Vector是Netflix开源的主机级性能监控框架,向每位工程师的浏览器提供精心挑选的高分辨率系统和应用程序指标. 登录到系统并从shell运行大量命令是一种选择,但是通常涉及的复杂性可能成 ...
- swagger-codegen自动生成代码工具的介绍与使用
一.Swagger Codegen简介 Swagger Codegen是一个开源的代码生成器,根据Swagger定义的RESTful API可以自动建立服务端和客户端的连接.Swagger Codeg ...
- Swift学习字符串、数组、字典
一.字符串的使用 let wiseWords = "\"I am a handsome\"-boy" var emptyString = "" ...
- WireShark基本抓包数据分析
WireShark抓包数据分析: 1.TCP报文格式 • 源端口.目的端口:16位长.标识出远端和本地的端口号. • 顺序号:32位长.表明了发送的数据报的顺序. • 确认号:32位长.希望收到 ...