2023-11-30 通过中缀表达式转换后缀表达式, 用C语言完成一个简单的计算器


点击 <C 语言编程核心突破> 快速C语言入门


通过中缀表达式转换后缀表达式, 用C语言完成一个简单的计算器


前言

要解决问题: 在练习用Qt完成一个简单的计算器时, 需要将一个文本计算式转换为C语言可使用的模式, 即后缀表达式, 规则还是挺繁复的.

想到的思路: 查文档, 了解中缀表达式转换为后缀表达式.

其它的补充: 需要用到栈, 这个基本功一定要扎实.


一、中缀表达式和后缀表达式 (AI辅助)

中缀表达式是指常见的数学表达式,如 2 + 3 * 4 - 5,其中运算符位于操作数之间。

中缀表达式通常需要通过加入括号来明确运算顺序。

后缀表达式(也称为逆波兰表达式)是一种不需要括号的表达式表示方式,其中运算符位于其相应的操作数之后。

例如,上述中缀表达式的后缀形式为 2 3 4 * + 5 -

在计算机科学中,后缀表达式比中缀表达式更容易被计算机算法处理和计算,因为它们没有嵌套括号的优先级问题。

因此,在编写计算机程序解析表达式时,通常会将中缀表达式转换为等效的后缀表达式以便更轻松地处理它们。

二、中缀转后缀规则及后缀运算规则 (AI辅助)

在后缀表达式中,运算符总是在它们所操作的两个操作数之后出现。

例如,对于后缀表达式 “3 4 + 5 *”,运算规则如下:

  1. 先将操作数 3 和 4 压入栈中。

  2. 遇到 “+” 运算符,弹出栈顶的 3 和 4 进行加法运算,结果为 7,再将结果 7 压入栈中。

  3. 遇到操作数 5,将其压入栈中。

  4. 遇到 “*” 运算符,弹出栈顶的 7 和 5 进行乘法运算,结果为 35,再将结果 35 压入栈中。

  5. 后缀表达式中的所有元素都被处理后,栈中只剩下一个元素 35,即为后缀表达式的计算结果。

具体规则见代码注释:

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 节点
struct node
{
    int flag;
    int value;
    struct node *next;
};

// 栈
typedef struct node *Stack;

// 压栈
void push(Stack *stack, int flag, int value)
{
    struct node *head = malloc(sizeof(struct node));
    head->flag = flag;
    head->value = value;
    head->next = *stack;
    *stack = head;
}

// 出栈
int pop(Stack *stack)
{
    int rest = (*stack)->value;
    Stack temp = *stack;
    *stack = (*stack)->next;
    free(temp);
    return rest;
}

// 判断栈是否为空
int empty(Stack *stack)
{
    return (*stack) == NULL;
}

// 栈顶元素
int top(Stack *stack)
{
    int rest = (*stack)->value;
    return rest;
}

// 栈顶flag
int topFlag(Stack *stack)
{
    return (*stack)->flag;
}

// 释放栈
void freeStack(Stack *stack)
{
    while (*stack)
    {
        struct node *head = *stack;
        *stack = (*stack)->next;
        free(head);
    }
}

// 反转栈
void reverse(Stack *stack)
{
    if (!(*stack))
    {
        return;
    }

    Stack head;
    Stack tail = NULL;

    while (*stack)
    {
        head = *stack;
        *stack = (*stack)->next;
        head->next = tail;
        tail = head;
    }
    *stack = head;
}

// 返回优先级
int priority(char operate)
{
    switch (operate)
    {
    case '+':
    case '-':
        return 1;
    case '*':
    case '/':
    case '%':
        return 2;
    default:
        return 0;
    }
}

// 判断操作符
int isOperator(char operator)
{
    return (operator== '+' || operator== '-' || operator== '*' || operator==
            '/' ||
            operator== '%');
}

// 判断左括号
int isLeftParenthesis(char operator)
{
    return operator== '(';
}

// 判断右括号
int isRightParenthesis(char operator)
{
    return operator== ')';
}

// 中缀表达式转后缀表达式的规则如下:
void convertToPostfix(char *input, Stack *postfix)
{
    Stack operateStack = NULL;
    static char number[32];

    // 1.从左到右遍历中缀表达式的每个元素。
    for (int i = 0; input[i] != '\0'; i++)
    {
        // 2.如果当前元素是数字,则将其加入后缀表达式中。
        if (isdigit(input[i]))
        {
            int num = 0;
            while (isdigit(input[i]))
            {
                number[num++] = input[i++];
            }
            number[num] = '\0';
            i--;
            push(postfix, 1, atoi(number));
        }
        // 3.如果当前元素是操作符,则执行以下步骤:
        //   a.如果该操作符是左括号“(”,则将其加入操作符栈中。
        else if (isLeftParenthesis(input[i]))
        {
            push(&operateStack, 0, input[i]);
        }
        //   b.如果该操作符是右括号“)”,则将操作符栈中的操作符弹出并加入后缀表达式中,直到遇到左括号为止。
        else if (isRightParenthesis(input[i]))
        {
            while (!isLeftParenthesis((char)top(&operateStack)))
            {
                push(postfix, 0, pop(&operateStack));
            }
            pop(&operateStack);
        }
        else if (isOperator(input[i]))
        {
            //   c.如果该操作符的优先级比操作符栈顶操作符的优先级低或相等
            //     则将操作符栈中的操作符弹出并加入后缀表达式中
            //     直到不存在比当前操作符优先级高的操作符为止。
            while (!empty(&operateStack) &&
                   priority(input[i]) <= priority((char)top(&operateStack)))
            {
                push(postfix, 0, pop(&operateStack));
            }
            //     将当前操作符加入操作符栈中。
            //   d.如果该操作符的优先级比操作符栈顶操作符的优先级高,则将当前操作符加入操作符栈中。
            push(&operateStack, 0, input[i]);
        }
    }
    // 4.当中缀表达式遍历完后,将操作符栈中的所有操作符依次弹出并加入后缀表达式中。
    while (!empty(&operateStack))
    {
        push(postfix, 0, pop(&operateStack));
    }
    freeStack(&operateStack);
    reverse(postfix);
}

// 计算
int calculate(int operand1, int operand2, char operate)
{
    switch (operate)
    {
    case '+':
        return operand1 + operand2;
    case '-':
        return operand1 - operand2;
    case '*':
        return operand1 * operand2;
    case '/':
        return operand1 / operand2;
    case '%':
        return operand1 % operand2;
    default:
        return 0;
    }
}

// 计算后缀表达式的规则如下:
int evaluatePostfix(Stack *postfix)
{
    Stack stack = NULL;

    // 1.从左到右扫描后缀表达式。
    while (*postfix)
    {
        // 2.遇到操作数时,将其压入操作数栈中。
        if ((*postfix)->flag)
        {
            push(&stack, 1, pop(postfix));
        }
        // 3.遇到运算符时,弹出栈顶的两个操作数,执行该运算符的计算,并将结果压入操作数栈中。
        else if (!(*postfix)->flag)
        {
            int operand2 = pop(&stack);
            int operand1 = pop(&stack);
            int result = calculate(operand1, operand2, (char)pop(postfix));
            push(&stack, 1, result);
        }
    }
    // 4.重复上述过程,直到后缀表达式中的所有元素都被处理。
    // 5.最后,操作数栈中只剩下一个数,即为后缀表达式的计算结果。
    int result = pop(&stack);
    freeStack(&stack);
    return result;
}

// 打印后缀表达式栈
void printStack(Stack stack)
{
    while (stack)
    {
        if (stack->flag)
        {
            printf("%d ", stack->value);
            stack = stack->next;
        }
        else
        {
            printf("%c ", stack->value);
            stack = stack->next;
        }
    }
    printf("\n");
}

// 测试
int main()
{
    char input[128];
    Stack postfix = NULL;

    printf("请输入含加减乘除、求模及括号的复杂算式:");
    scanf("%s", input);

    convertToPostfix(input, &postfix);
    printf("后缀表达式为:\n");
    printStack(postfix);

    int result = evaluatePostfix(&postfix);
    printf("计算结果为:%d\n", result);

    freeStack(&postfix);

    return 0;
}

qt加个gui:

Widget.cpp

#include "Widget.h"
#include "./ui_Widget.h"
#include "jisuanqi.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    this->setMaximumSize(200, 290);
    this->setMinimumSize(200, 290);
    this->setWindowTitle("计算器");
    QFont f("仿宋", 14);
    ui->resultLineEdit->setFont(f);

    // 按钮图片
    QIcon con("E:\\clangC++\\learnQT\\Learn_2\\img\\delete.jpg");
    ui->delButton->setIcon(con);

    // ui->resultButton->setStyleSheet("background: yellow");
}

Widget::~Widget()
{
    delete ui;
}

void Widget::on_num0Button_clicked()
{
    expression += "0";
    ui->resultLineEdit->setText(expression);
}

void Widget::on_num1Button_clicked()
{
    expression += "1";
    ui->resultLineEdit->setText(expression);
}

void Widget::on_num2Button_clicked()
{
    expression += "2";
    ui->resultLineEdit->setText(expression);
}

void Widget::on_num3Button_clicked()
{
    expression += "3";
    ui->resultLineEdit->setText(expression);
}

void Widget::on_num4Button_clicked()
{
    expression += "4";
    ui->resultLineEdit->setText(expression);
}

void Widget::on_num5Button_clicked()
{
    expression += "5";
    ui->resultLineEdit->setText(expression);
}

void Widget::on_num6Button_clicked()
{
    expression += "6";
    ui->resultLineEdit->setText(expression);
}

void Widget::on_num7Button_clicked()
{
    expression += "7";
    ui->resultLineEdit->setText(expression);
}

void Widget::on_num8Button_clicked()
{
    expression += "8";
    ui->resultLineEdit->setText(expression);
}

void Widget::on_num9Button_clicked()
{
    expression += "9";
    ui->resultLineEdit->setText(expression);
}

void Widget::on_leftKuohaoButton_clicked()
{
    expression += "(";
    ui->resultLineEdit->setText(expression);
}

void Widget::on_rughtKuohaoButton_clicked()
{
    expression += ")";
    ui->resultLineEdit->setText(expression);
}

void Widget::on_addButton_clicked()
{
    expression += "+";
    ui->resultLineEdit->setText(expression);
}

void Widget::on_subButton_clicked()
{
    expression += "-";
    ui->resultLineEdit->setText(expression);
}

void Widget::on_mulButton_clicked()
{
    expression += "*";
    ui->resultLineEdit->setText(expression);
}

void Widget::on_devButton_clicked()
{
    expression += "/";
    ui->resultLineEdit->setText(expression);
}

void Widget::on_resultButton_clicked()
{
    //  qs >> numSum;
    //  // while (!qs.atEnd())
    //  //{
    //  qs >> qchr;
    //  qs >> numA;
    //  switch (qchr)
    //  {
    //  case '+':
    //      numSum += numA;
    //      break;
    //  case '-':
    //      numSum -= numA;
    //      break;
    //  case '*':
    //      numSum *= numA;
    //      break;
    //  case '/':
    //      numSum /= numA;
    //      break;
    //  default:
    //      break;
    //  }
    //  QString qs;
    //  for (QChar &var : expression)
    //  {
    //      if (var.isNumber())
    //      {
    //          continue;
    //      }
    //      else
    //      {
    //          qs += var;
    //          var = ' ';
    //      }
    //  }

    //  QTextStream qts(&qs);
    //  QTextStream qtn(&expression);
    //  int numA;
    //  int numSum = 0;
    //  char qchr;
    //  qtn >> numSum;
    //  while (!qts.atEnd())
    //  {
    //      qts >> qchr;
    //      qtn >> numA;
    //      switch (qchr)
    //      {
    //      case '+':
    //          numSum += numA;
    //          break;
    //      case '-':
    //          numSum -= numA;
    //          break;
    //      case '*':
    //          numSum *= numA;
    //          break;
    //      case '/':
    //          numSum /= numA;
    //          break;
    //      default:
    //          break;
    //      }
    //  }

    char input[128];
    Stack postfix = NULL;

    strncpy(input, expression.toStdString().data(), 128);

    convertToPostfix(input, &postfix);

    int result = evaluatePostfix(&postfix);

    freeStack(&postfix);
    expression.clear();
    expression += QString::number(result);
    ui->resultLineEdit->setText(expression);
    //}
}

void Widget::on_clearButton_clicked()
{
    expression.clear();
    ui->resultLineEdit->clear();
}

void Widget::on_delButton_clicked()
{
    expression.chop(1);
    ui->resultLineEdit->setText(expression);
}

Widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QTextStream>
#include <QWidget>

QT_BEGIN_NAMESPACE
namespace Ui
{
class Widget;
}
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

  public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

  private slots:
    void on_num0Button_clicked();
    void on_num1Button_clicked();
    void on_num2Button_clicked();
    void on_num3Button_clicked();
    void on_num4Button_clicked();
    void on_num5Button_clicked();
    void on_num6Button_clicked();
    void on_num7Button_clicked();
    void on_num8Button_clicked();
    void on_num9Button_clicked();

    void on_leftKuohaoButton_clicked();

    void on_rughtKuohaoButton_clicked();

    void on_addButton_clicked();

    void on_subButton_clicked();

    void on_mulButton_clicked();

    void on_devButton_clicked();

    void on_resultButton_clicked();

    void on_clearButton_clicked();

    void on_delButton_clicked();

  private:
    Ui::Widget *ui;
    QString expression;
};
#endif // WIDGET_H

main.cpp

#include "Widget.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
}

Widget.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>Widget</class>
 <widget class="QWidget" name="Widget">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>197</width>
    <height>293</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Widget</string>
  </property>
  <widget class="QLineEdit" name="resultLineEdit">
   <property name="geometry">
    <rect>
     <x>10</x>
     <y>10</y>
     <width>181</width>
     <height>41</height>
    </rect>
   </property>
  </widget>
  <widget class="QWidget" name="layoutWidget">
   <property name="geometry">
    <rect>
     <x>10</x>
     <y>60</y>
     <width>180</width>
     <height>226</height>
    </rect>
   </property>
   <layout class="QGridLayout" name="gridLayout">
    <item row="2" column="3">
     <widget class="QPushButton" name="devButton">
      <property name="minimumSize">
       <size>
        <width>40</width>
        <height>40</height>
       </size>
      </property>
      <property name="maximumSize">
       <size>
        <width>40</width>
        <height>40</height>
       </size>
      </property>
      <property name="font">
       <font>
        <family>阿里巴巴普惠体 B</family>
        <pointsize>15</pointsize>
        <bold>true</bold>
       </font>
      </property>
      <property name="text">
       <string>/</string>
      </property>
     </widget>
    </item>
    <item row="1" column="3">
     <widget class="QPushButton" name="mulButton">
      <property name="minimumSize">
       <size>
        <width>40</width>
        <height>40</height>
       </size>
      </property>
      <property name="maximumSize">
       <size>
        <width>40</width>
        <height>40</height>
       </size>
      </property>
      <property name="font">
       <font>
        <family>阿里巴巴普惠体 B</family>
        <pointsize>15</pointsize>
        <bold>true</bold>
       </font>
      </property>
      <property name="text">
       <string>*</string>
      </property>
     </widget>
    </item>
    <item row="1" column="0">
     <widget class="QPushButton" name="num7Button">
      <property name="minimumSize">
       <size>
        <width>40</width>
        <height>40</height>
       </size>
      </property>
      <property name="maximumSize">
       <size>
        <width>40</width>
        <height>40</height>
       </size>
      </property>
      <property name="font">
       <font>
        <family>阿里巴巴普惠体 B</family>
        <pointsize>15</pointsize>
        <bold>true</bold>
       </font>
      </property>
      <property name="text">
       <string>7</string>
      </property>
     </widget>
    </item>
    <item row="5" column="2">
     <widget class="QPushButton" name="rughtKuohaoButton">
      <property name="minimumSize">
       <size>
        <width>40</width>
        <height>40</height>
       </size>
      </property>
      <property name="maximumSize">
       <size>
        <width>40</width>
        <height>40</height>
       </size>
      </property>
      <property name="font">
       <font>
        <family>阿里巴巴普惠体 B</family>
        <pointsize>15</pointsize>
        <bold>true</bold>
       </font>
      </property>
      <property name="text">
       <string>)</string>
      </property>
     </widget>
    </item>
    <item row="4" column="3" rowspan="2">
     <widget class="QPushButton" name="resultButton">
      <property name="minimumSize">
       <size>
        <width>40</width>
        <height>40</height>
       </size>
      </property>
      <property name="maximumSize">
       <size>
        <width>40</width>
        <height>90</height>
       </size>
      </property>
      <property name="font">
       <font>
        <family>阿里巴巴普惠体 B</family>
        <pointsize>15</pointsize>
        <bold>true</bold>
       </font>
      </property>
      <property name="styleSheet">
       <string notr="true">background-color: rgb(85, 255, 255);</string>
      </property>
      <property name="text">
       <string>=</string>
      </property>
     </widget>
    </item>
    <item row="1" column="1">
     <widget class="QPushButton" name="num8Button">
      <property name="minimumSize">
       <size>
        <width>40</width>
        <height>40</height>
       </size>
      </property>
      <property name="maximumSize">
       <size>
        <width>40</width>
        <height>40</height>
       </size>
      </property>
      <property name="font">
       <font>
        <family>阿里巴巴普惠体 B</family>
        <pointsize>15</pointsize>
        <bold>true</bold>
       </font>
      </property>
      <property name="text">
       <string>8</string>
      </property>
     </widget>
    </item>
    <item row="2" column="1">
     <widget class="QPushButton" name="num5Button">
      <property name="minimumSize">
       <size>
        <width>40</width>
        <height>40</height>
       </size>
      </property>
      <property name="maximumSize">
       <size>
        <width>40</width>
        <height>40</height>
       </size>
      </property>
      <property name="font">
       <font>
        <family>阿里巴巴普惠体 B</family>
        <pointsize>15</pointsize>
        <bold>true</bold>
       </font>
      </property>
      <property name="text">
       <string>5</string>
      </property>
     </widget>
    </item>
    <item row="2" column="0" rowspan="2">
     <widget class="QPushButton" name="num4Button">
      <property name="minimumSize">
       <size>
        <width>40</width>
        <height>40</height>
       </size>
      </property>
      <property name="maximumSize">
       <size>
        <width>40</width>
        <height>40</height>
       </size>
      </property>
      <property name="font">
       <font>
        <family>阿里巴巴普惠体 B</family>
        <pointsize>15</pointsize>
        <bold>true</bold>
       </font>
      </property>
      <property name="text">
       <string>4</string>
      </property>
     </widget>
    </item>
    <item row="4" column="0">
     <widget class="QPushButton" name="num1Button">
      <property name="minimumSize">
       <size>
        <width>40</width>
        <height>40</height>
       </size>
      </property>
      <property name="maximumSize">
       <size>
        <width>40</width>
        <height>40</height>
       </size>
      </property>
      <property name="font">
       <font>
        <family>阿里巴巴普惠体 B</family>
        <pointsize>15</pointsize>
        <bold>true</bold>
       </font>
      </property>
      <property name="text">
       <string>1</string>
      </property>
     </widget>
    </item>
    <item row="5" column="0">
     <widget class="QPushButton" name="leftKuohaoButton">
      <property name="minimumSize">
       <size>
        <width>40</width>
        <height>40</height>
       </size>
      </property>
      <property name="maximumSize">
       <size>
        <width>40</width>
        <height>40</height>
       </size>
      </property>
      <property name="font">
       <font>
        <family>阿里巴巴普惠体 B</family>
        <pointsize>15</pointsize>
        <bold>true</bold>
       </font>
      </property>
      <property name="text">
       <string>(</string>
      </property>
     </widget>
    </item>
    <item row="4" column="1">
     <widget class="QPushButton" name="num2Button">
      <property name="minimumSize">
       <size>
        <width>40</width>
        <height>40</height>
       </size>
      </property>
      <property name="maximumSize">
       <size>
        <width>40</width>
        <height>40</height>
       </size>
      </property>
      <property name="font">
       <font>
        <family>阿里巴巴普惠体 B</family>
        <pointsize>15</pointsize>
        <bold>true</bold>
       </font>
      </property>
      <property name="text">
       <string>2</string>
      </property>
     </widget>
    </item>
    <item row="2" column="2">
     <widget class="QPushButton" name="num6Button">
      <property name="minimumSize">
       <size>
        <width>40</width>
        <height>40</height>
       </size>
      </property>
      <property name="maximumSize">
       <size>
        <width>40</width>
        <height>40</height>
       </size>
      </property>
      <property name="font">
       <font>
        <family>阿里巴巴普惠体 B</family>
        <pointsize>15</pointsize>
        <bold>true</bold>
       </font>
      </property>
      <property name="text">
       <string>6</string>
      </property>
     </widget>
    </item>
    <item row="4" column="2">
     <widget class="QPushButton" name="num3Button">
      <property name="minimumSize">
       <size>
        <width>40</width>
        <height>40</height>
       </size>
      </property>
      <property name="maximumSize">
       <size>
        <width>40</width>
        <height>40</height>
       </size>
      </property>
      <property name="font">
       <font>
        <family>阿里巴巴普惠体 B</family>
        <pointsize>15</pointsize>
        <bold>true</bold>
       </font>
      </property>
      <property name="text">
       <string>3</string>
      </property>
     </widget>
    </item>
    <item row="5" column="1">
     <widget class="QPushButton" name="num0Button">
      <property name="minimumSize">
       <size>
        <width>40</width>
        <height>40</height>
       </size>
      </property>
      <property name="maximumSize">
       <size>
        <width>40</width>
        <height>40</height>
       </size>
      </property>
      <property name="font">
       <font>
        <family>阿里巴巴普惠体 B</family>
        <pointsize>15</pointsize>
        <bold>true</bold>
       </font>
      </property>
      <property name="text">
       <string>0</string>
      </property>
     </widget>
    </item>
    <item row="1" column="2">
     <widget class="QPushButton" name="num9Button">
      <property name="minimumSize">
       <size>
        <width>40</width>
        <height>40</height>
       </size>
      </property>
      <property name="maximumSize">
       <size>
        <width>40</width>
        <height>40</height>
       </size>
      </property>
      <property name="font">
       <font>
        <family>阿里巴巴普惠体 B</family>
        <pointsize>15</pointsize>
        <bold>true</bold>
       </font>
      </property>
      <property name="text">
       <string>9</string>
      </property>
     </widget>
    </item>
    <item row="0" column="0">
     <widget class="QPushButton" name="clearButton">
      <property name="minimumSize">
       <size>
        <width>40</width>
        <height>40</height>
       </size>
      </property>
      <property name="maximumSize">
       <size>
        <width>40</width>
        <height>40</height>
       </size>
      </property>
      <property name="font">
       <font>
        <family>阿里巴巴普惠体 B</family>
        <pointsize>15</pointsize>
        <bold>true</bold>
       </font>
      </property>
      <property name="text">
       <string>c</string>
      </property>
     </widget>
    </item>
    <item row="0" column="1">
     <widget class="QPushButton" name="addButton">
      <property name="minimumSize">
       <size>
        <width>40</width>
        <height>40</height>
       </size>
      </property>
      <property name="maximumSize">
       <size>
        <width>40</width>
        <height>40</height>
       </size>
      </property>
      <property name="font">
       <font>
        <family>阿里巴巴普惠体 B</family>
        <pointsize>15</pointsize>
        <bold>true</bold>
       </font>
      </property>
      <property name="text">
       <string>+</string>
      </property>
     </widget>
    </item>
    <item row="0" column="2">
     <widget class="QPushButton" name="subButton">
      <property name="minimumSize">
       <size>
        <width>40</width>
        <height>40</height>
       </size>
      </property>
      <property name="maximumSize">
       <size>
        <width>40</width>
        <height>40</height>
       </size>
      </property>
      <property name="font">
       <font>
        <family>阿里巴巴普惠体 B</family>
        <pointsize>15</pointsize>
        <bold>true</bold>
       </font>
      </property>
      <property name="text">
       <string>-</string>
      </property>
     </widget>
    </item>
    <item row="0" column="3">
     <widget class="QPushButton" name="delButton">
      <property name="minimumSize">
       <size>
        <width>40</width>
        <height>40</height>
       </size>
      </property>
      <property name="maximumSize">
       <size>
        <width>40</width>
        <height>40</height>
       </size>
      </property>
      <property name="font">
       <font>
        <family>阿里巴巴普惠体 B</family>
        <pointsize>15</pointsize>
        <bold>true</bold>
       </font>
      </property>
      <property name="text">
       <string/>
      </property>
      <property name="iconSize">
       <size>
        <width>22</width>
        <height>22</height>
       </size>
      </property>
     </widget>
    </item>
   </layout>
  </widget>
 </widget>
 <resources/>
 <connections/>
</ui>

jisuanqi.h

#ifndef JISUANQI_H
#define JISUANQI_H

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 节点
struct node
{
    int flag;
    int value;
    struct node *next;
};

// 栈
typedef struct node *Stack;

// 压栈
void push(Stack *stack, int flag, int value)
{
    struct node *head = (struct node *)malloc(sizeof(struct node));
    head->flag = flag;
    head->value = value;
    head->next = *stack;
    *stack = head;
}

// 出栈
int pop(Stack *stack)
{
    int rest = (*stack)->value;
    Stack temp = *stack;
    *stack = (*stack)->next;
    free(temp);
    return rest;
}

// 判断栈是否为空
int empty(Stack *stack)
{
    return (*stack) == NULL;
}

// 栈顶元素
int top(Stack *stack)
{
    int rest = (*stack)->value;
    return rest;
}

// 栈顶flag
int topFlag(Stack *stack)
{
    return (*stack)->flag;
}

// 释放栈
void freeStack(Stack *stack)
{
    while (*stack)
    {
        struct node *head = *stack;
        *stack = (*stack)->next;
        free(head);
    }
}

// 反转栈
void reverse(Stack *stack)
{
    if (!(*stack))
    {
        return;
    }

    Stack head;
    Stack tail = NULL;

    while (*stack)
    {
        head = *stack;
        *stack = (*stack)->next;
        head->next = tail;
        tail = head;
    }
    *stack = head;
}

// 返回优先级
int priority(char operate)
{
    switch (operate)
    {
    case '+':
    case '-':
        return 1;
    case '*':
    case '/':
    case '%':
        return 2;
    default:
        return 0;
    }
}

// 判断操作符
int isoprtr(char oprtr)
{
    return (oprtr== '+' || oprtr== '-' || oprtr== '*' || oprtr==
            '/' ||
            oprtr== '%');
}

// 判断左括号
int isLeftParenthesis(char oprtr)
{
    return oprtr== '(';
}

// 判断右括号
int isRightParenthesis(char oprtr)
{
    return oprtr== ')';
}

// 中缀表达式转后缀表达式的规则如下:
void convertToPostfix(char *input, Stack *postfix)
{
    Stack operateStack = NULL;
    static char number[32];

    // 1.从左到右遍历中缀表达式的每个元素。
    for (int i = 0; input[i] != '\0'; i++)
    {
        // 2.如果当前元素是数字,则将其加入后缀表达式中。
        if (isdigit(input[i]))
        {
            int num = 0;
            while (isdigit(input[i]))
            {
                number[num++] = input[i++];
            }
            number[num] = '\0';
            i--;
            push(postfix, 1, atoi(number));
        }
        // 3.如果当前元素是操作符,则执行以下步骤:
        //   a.如果该操作符是左括号“(”,则将其加入操作符栈中。
        else if (isLeftParenthesis(input[i]))
        {
            push(&operateStack, 0, input[i]);
        }
        //   b.如果该操作符是右括号“)”,则将操作符栈中的操作符弹出并加入后缀表达式中,直到遇到左括号为止。
        else if (isRightParenthesis(input[i]))
        {
            while (!isLeftParenthesis((char)top(&operateStack)))
            {
                push(postfix, 0, pop(&operateStack));
            }
            pop(&operateStack);
        }
        else if (isoprtr(input[i]))
        {
            //   c.如果该操作符的优先级比操作符栈顶操作符的优先级低或相等
            //     则将操作符栈中的操作符弹出并加入后缀表达式中
            //     直到不存在比当前操作符优先级高的操作符为止。
            while (!empty(&operateStack) &&
                   priority(input[i]) <= priority((char)top(&operateStack)))
            {
                push(postfix, 0, pop(&operateStack));
            }
            //     将当前操作符加入操作符栈中。
            //   d.如果该操作符的优先级比操作符栈顶操作符的优先级高,则将当前操作符加入操作符栈中。
            push(&operateStack, 0, input[i]);
        }
    }
    // 4.当中缀表达式遍历完后,将操作符栈中的所有操作符依次弹出并加入后缀表达式中。
    while (!empty(&operateStack))
    {
        push(postfix, 0, pop(&operateStack));
    }
    freeStack(&operateStack);
    reverse(postfix);
}

// 计算
int calculate(int operand1, int operand2, char operate)
{
    switch (operate)
    {
    case '+':
        return operand1 + operand2;
    case '-':
        return operand1 - operand2;
    case '*':
        return operand1 * operand2;
    case '/':
        return operand1 / operand2;
    case '%':
        return operand1 % operand2;
    default:
        return 0;
    }
}

// 计算后缀表达式的规则如下:
int evaluatePostfix(Stack *postfix)
{
    Stack stack = NULL;

    // 1.从左到右扫描后缀表达式。
    while (*postfix)
    {
        // 2.遇到操作数时,将其压入操作数栈中。
        if ((*postfix)->flag)
        {
            push(&stack, 1, pop(postfix));
        }
        // 3.遇到运算符时,弹出栈顶的两个操作数,执行该运算符的计算,并将结果压入操作数栈中。
        else if (!(*postfix)->flag)
        {
            int operand2 = pop(&stack);
            int operand1 = pop(&stack);
            int result = calculate(operand1, operand2, (char)pop(postfix));
            push(&stack, 1, result);
        }
    }
    // 4.重复上述过程,直到后缀表达式中的所有元素都被处理。
    // 5.最后,操作数栈中只剩下一个数,即为后缀表达式的计算结果。
    int result = pop(&stack);
    freeStack(&stack);
    return result;
}

// 打印后缀表达式栈
void printStack(Stack stack)
{
    while (stack)
    {
        if (stack->flag)
        {
            printf("%d ", stack->value);
            stack = stack->next;
        }
        else
        {
            printf("%c ", stack->value);
            stack = stack->next;
        }
    }
    printf("\n");
}

#endif // JISUANQI_H


总结

用C语言对字符串算式做语法分析并得出计算结果, 是很多教材的标准示例, 但并不简单, 属于数据结构和算法的一个类型, 考验栈结构和操作函数, 中缀转后缀算法, 后缀计算算法等, 慢慢体会.


点击 <C 语言编程核心突破> 快速C语言入门


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不停感叹的老林_<C 语言编程核心突破>

不打赏的人, 看完也学不会.

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值