当前位置: 首页 > news >正文

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


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


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

  • 前言
  • 一、中缀表达式和后缀表达式 (AI辅助)
  • 二、中缀转后缀规则及后缀运算规则 (AI辅助)
  • 总结


前言

要解决问题: 在练习用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;
}

总结

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


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


http://www.lryc.cn/news/249715.html

相关文章:

  • 设计模式总目录
  • 通俗理解词向量模型,预训练模型,Transfomer,Bert和GPT的发展脉络和如何实践
  • 键入网址到网页显示,期间发生了什么?(计算机网络)
  • python-GC机制、装饰器、生成器、迭代器、三元表达式、列表生成式、生成器表达式、函数递归、面向对象、
  • Linux命令--根据端口号查看进程号(PID)
  • LangChain 9 模型Model I/O 聊天提示词ChatPromptTemplate, 少量样本提示词FewShotPrompt
  • 使用 Vue3 + Pinia + Ant Design Vue3 搭建后台管理系统
  • SpringCloud核心组件
  • 基于C++11实现将IP地址、端口号和连接状态写入文件
  • 非空断言,
  • Spark---创建DataFrame的方式
  • 瑜伽学习零基础入门,各种瑜伽教学方法全集
  • pycharm编译报错处理
  • “华为杯”研究生数学建模竞赛2019年-【华为杯】E题:基于多变量的全球气候与极端天气模型的构建与应用(附python代码实现)
  • 冒泡排序(适合编程新手的体质)
  • pdfjs,pdf懒加载
  • K8s 多租户方案的挑战与价值
  • 单链表相关经典算法OJ题:移除链表元素
  • 【JUC】十九、volatile与内存屏障
  • 下载MySQL JDBC驱动的方法
  • C/C++ 实现FTP文件上传下载
  • 第十三章 python之爬虫
  • scrum 敏捷开发
  • 亚信科技AntDB数据库完成中国信通院数据库迁移工具专项测试
  • 深度学习(一):Pytorch之YOLOv8目标检测
  • EasyExcel如何读取全部Sheet页数据方法
  • GDPU 数据结构 天码行空12
  • 什么是 Proxy?
  • Vue系列:Vue Element UI中,使用按钮实现视频的播放、停止、停止后继续播放、播放完成后重新播放功能
  • .Net 8 Blazor下 Auto交互渲染模式试用