zoukankan      html  css  js  c++  java
  • Qt之加减乘除四则运算-支持负数

    一、效果展示

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

    图1 四则运算展示

    测试代码如下

     1 void lineedit::CalculateExpression()
     2 {
     3     QString reExp("1 + 2.3 * (23 + 3)");
     4     QString res = change(reExp);//0 1 - 2.3 23 3 + * +
     5 
     6     QString reExp2("1*(-3)+2*(3+3)");
     7     QString res2 = change(reExp2);
     8 
     9     QString reExp3("2*-3+-2.1*(3+3)");
    10     repairExpress(reExp3);
    11     QString res3 = change(reExp3);
    12 
    13     QString reExp4("2*(-3)+-2.1*(3+3)");
    14     repairExpress(reExp4);
    15     QString res4 = change(reExp4);
    16 
    17     QString reExp5("2*(0-(1.1-3)*3)+-2.1*(3+3)");
    18     repairExpress(reExp5);
    19     QString res5 = change(reExp5);
    20 
    21     qDebug() << reExp << '	'<< res << ":" << CalExp(res.split(' ', QString::SkipEmptyParts));
    22     qDebug() << reExp2 << '	'<< res2 << ":" << CalExp(res2.split(' ', QString::SkipEmptyParts));
    23     qDebug() << reExp3 << '	'<< res3 << ":" << CalExp(res3.split(' ', QString::SkipEmptyParts));
    24     qDebug() << reExp4 << '	'<< res4 << ":" << CalExp(res4.split(' ', QString::SkipEmptyParts));
    25     qDebug() << reExp5 << '	'<< res5 << ":" << CalExp(res5.split(' ', QString::SkipEmptyParts));
    26 }

    二、一些小技巧

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

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

     1 //针对负号进行字符串修复 例如:-1*-3+2*(3+3) -> (0-1)*(0-3)+2*(3+3)
     2 void repairExpress(QString & express)
     3 {
     4     bool repair = false;
     5     int lpos = -1, rpos = -1;
     6     QString result;
     7     for(int i = 0; i < express.size(); ++i)
     8     {
     9         QChar c = express[i];
    10         if (c == '+' || c == '-' || c == '*' || c == '/')//出现符号时记录
    11         {
    12             if (repair)
    13             {
    14                 result.append(')');
    15                 lpos = -1;
    16                 repair = false;
    17             }
    18 
    19             if (c == '-'&&
    20                 (i == 0  || lpos != -1 && lpos == i - 1))
    21             {
    22                 result.append('(');
    23                 repair = true;
    24             }
    25 
    26             lpos = i;
    27         }
    28 
    29         result.append(c);
    30     }
    31 
    32     express = result;
    33 }

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

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

    三、后缀表达式

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

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

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

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

    下边我直接给出实现代码

     1 //中缀表达式转后缀表达式
     2 QString change(const QString & s_mid)
     3 {  
     4     QString result;
     5     QStack<QChar> stk;
     6 
     7     QMap<QChar, int> op;//利用map来实现运算符对应其优先级
     8     op['(']=0;
     9     op[')']=0;
    10     op['+']=1;
    11     op['-']=1;
    12     op['*']=2;
    13     op['/']=2;
    14     auto iter = s_mid.begin();
    15     for(int i = 0; i < s_mid.size(); ++i)
    16     {
    17         QChar c = s_mid[i];
    18         if (c == ' ')
    19         {
    20             continue;
    21         }
    22         if (c == '-' &&
    23             (i == 0 || op.contains(s_mid[i-1])))//可能为负号
    24         {
    25             result.append('0');
    26         }
    27         if(op.contains(c))//判断该元素是否为运算符
    28         {
    29             if(c == ')')//情况2
    30             {
    31                 while(stk.top() != '(')
    32                 {
    33                     rettifyExpress(result);
    34                     result.append(stk.top());
    35                     stk.pop();
    36                 }
    37                 stk.pop();
    38             }
    39             else if(stk.empty() || c == '(' || op[c] > op[stk.top()])//情况1、情况3
    40             {
    41                 stk.push(c);
    42             }
    43             else if(op[c] <= op[stk.top()])//情况3
    44             {
    45                 while(op[c] <= op[stk.top()] && (!stk.empty()))
    46                 {
    47                     rettifyExpress(result);
    48                     result.append(stk.top());
    49                     stk.pop();
    50                     if(stk.empty()) break;
    51                 }
    52                 stk.push(c);
    53             }
    54 
    55             rettifyExpress(result);
    56         }
    57         else
    58         {
    59             result.append(c);
    60         }
    61     }
    62 
    63     while(stk.empty() == false)//当中缀表达式输出完成,所有元素出栈
    64     {
    65         rettifyExpress(result);
    66         result.append(stk.top());
    67         stk.pop();
    68     }
    69 
    70     return result;
    71 }
    View Code

    四、表达式计算

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

     1 //计算表达式值
     2 double CalExp(const QStringList & express)
     3 {
     4     double result;
     5     QStack<QString> stk;
     6     for (int i = 0; i < express.size(); ++i)
     7     {
     8         QString item = express[i];
     9         if (item.size() == 1 && 
    10             (item.at(0) == "+" || item.at(0) == "-" || item.at(0) == "*" || item.at(0) == "/"))
    11         {
    12             double r = stk.pop().toDouble();
    13             double l = stk.pop().toDouble();
    14             switch(item.at(0).toLatin1())
    15             {
    16             case '+':
    17                 result = l + r;break;
    18             case '-':
    19                 result = l - r;break;
    20             case '*':
    21                 result = l * r;break;
    22             case '/':
    23                 result = l / r;break;
    24             }
    25 
    26             stk.push_back(QString::number(result));
    27         }
    28         else 
    29         {
    30             stk.push_back(item);
    31         }
    32     }
    33 
    34     return result;
    35 }

    五、下载链接

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

    参考文章:

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

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

  • 相关阅读:
    非阻塞式线程安全列表-ConcurrentLinkedDeque
    计数器
    Linux 查看服务器内存使用情况
    Oracle to_date, to_timestamp
    Hibernate session.flush() 使用
    阿里规约认证(题库附答案)
    多态性
    Java数据类型
    String类特点分析
    数组的定义
  • 原文地址:https://www.cnblogs.com/swarmbees/p/9356346.html
Copyright © 2011-2022 走看看