当前位置: 首页 > 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语言入门


相关文章:

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

点击 <C 语言编程核心突破> 快速C语言入门 通过中缀表达式转换后缀表达式, 用C语言完成一个简单的计算器 前言一、中缀表达式和后缀表达式 (AI辅助)二、中缀转后缀规则及后缀运算规则 (AI辅助)总结 前言 要解决问题: 在练习用Qt完成一个简单的计算器时, 需要将一个文本…...

设计模式总目录

目录 设计模式 1. 创建型模式 1.1 工厂方法模式 1.2 抽象工厂模式 1.3 单例模式 1.4 建造者模式 1.5原型模式 2. 结构型模式 2.1 适配器模式 2.2 装饰器模式 2.3 代理模式 2.4 外观模式 2.5 桥接模式 2.6 组合模式 2.7 享元模式 3. 行为型模式 3.1 策略模式 …...

通俗理解词向量模型,预训练模型,Transfomer,Bert和GPT的发展脉络和如何实践

最近研究GPT&#xff0c;深入的从transfomer的原理和代码看来一下&#xff0c;现在把学习的资料和自己的理解整理一下。 这个文章写的很通俗易懂&#xff0c;把transformer的来龙去脉&#xff0c;还举例了很多不错的例子。 Transformer通俗笔记&#xff1a;从Word2Vec、Seq2S…...

键入网址到网页显示,期间发生了什么?(计算机网络)

浏览器首先会对URL进行解析 下面以http://www.server.com/dir1/file1.html为例 当没有路径名时&#xff0c;就代表访问根目录下事先设置的默认文件&#xff0c;也就是 /index.html 或者 /default.html 对URL进行解析之后&#xff0c;浏览器确定了 Web 服务器和文件名&#x…...

python-GC机制、装饰器、生成器、迭代器、三元表达式、列表生成式、生成器表达式、函数递归、面向对象、

1 基础知识 1.1 GC机制 Python的垃圾回收&#xff0c;其实高级的语言都有自己的垃圾回收机制简称GC&#xff0c; python当中主要通过三种方式解决垃圾回收的方式&#xff0c;引用计数、标记清除、分代回收。引用计数&#xff1a;如果有新的引用指向对象&#xff0c;对象引用计…...

Linux命令--根据端口号查看进程号(PID)

Linux命令–根据端口号查看进程号&#xff08;PID&#xff09; 查找8080端口对应的进程号: netstat -nlp|grep :8297对应的进程号1061,如果想杀掉此进程&#xff0c;可以用一下命令&#xff1a; kill -9 1061...

LangChain 9 模型Model I/O 聊天提示词ChatPromptTemplate, 少量样本提示词FewShotPrompt

LangChain系列文章 LangChain 实现给动物取名字&#xff0c;LangChain 2模块化prompt template并用streamlit生成网站 实现给动物取名字LangChain 3使用Agent访问Wikipedia和llm-math计算狗的平均年龄LangChain 4用向量数据库Faiss存储&#xff0c;读取YouTube的视频文本搜索I…...

使用 Vue3 + Pinia + Ant Design Vue3 搭建后台管理系统

Vue3 & Ant Design Vue3基础 nodejs版本要求&#xff1a;node-v18.16.0-x64 nodejs基础配置 npm -v node -vnpm config set prefix "D:\software\nodejs\node_global" npm config set cache "D:\software\nodejs\node_cache"npm config get registry …...

SpringCloud核心组件

Eureka 注册中心&#xff0c;服务的注册与发现 Feign远程调用 Ribbon负载均衡&#xff0c;默认轮询 Hystrix 熔断 降级 Zuul微服务网关&#xff08;这个组件负责网络路由&#xff0c;可以做统一的降级、限流、认证授权、安全&#xff09; Eureka 微服务的功能主要有以下几…...

基于C++11实现将IP地址、端口号和连接状态写入文件

要基于C11实现将IP地址、端口号和连接状态写入文件&#xff0c;您可以使用std::ofstream类来打开文件并进行写入操作。以下是一个示例&#xff1a; #include <iostream> #include <fstream>void writeConnectionStatus(const std::string& ip, int port, bool…...

非空断言,

先看下TypeScript基础之非空断言操作符、可选链运算符、空值合并运算符-CSDN博客 我没有复现出来&#xff0c;但是我知道了它的作用 用 let str: string arg!; 代替 let str: string; if (arg) { str arg; } 非空断言&#xff08;!&#xff09;和不使用的区别在于对于…...

Spark---创建DataFrame的方式

1、读取json格式的文件创建DataFrame 注意&#xff1a; 1、可以两种方式读取json格式的文件。 2、df.show()默认显示前20行数据。 3、DataFrame原生API可以操作DataFrame。 4、注册成临时表时&#xff0c;表中的列默认按ascii顺序显示列。 df.createTempView("mytab…...

瑜伽学习零基础入门,各种瑜伽教学方法全集

一、教程描述 练习瑜伽的好处多多&#xff0c;能够保证平衡健康的身体基础&#xff0c;提升气质、塑造形体、陶冶情操&#xff0c;等等。本套教程是瑜伽的组合教程&#xff0c;共由33套视频教程组合而成&#xff0c;包含了塑身纤体&#xff0c;速效瘦身&#xff0c;四季养生&a…...

pycharm编译报错处理

1.c生成工具下载 https://visualstudio.microsoft.com/visual-cpp-build-tools/ 在这里插入图片描述 pip install pycocotools...

“华为杯”研究生数学建模竞赛2019年-【华为杯】E题:基于多变量的全球气候与极端天气模型的构建与应用(附python代码实现)

目录 摘 要: 一.问题重述 1.1 问题背景 1.2 问题提出 二.模型假设及符号设定...

冒泡排序(适合编程新手的体质)

冒泡排序&#xff1a;简单而高效的排序技巧 欢迎来到我们今天的博客&#xff0c;我们将一起探索计算机科学中最基本但同时也非常重要的概念之一&#xff1a;冒泡排序。无论你是编程新手还是有一些编程经验的读者&#xff0c;这篇博客都将帮助你更好地理解冒泡排序的原理和应用…...

pdfjs,pdf懒加载

PDF.js是一个使用JavaScript实现的PDF阅读器&#xff0c;它可以在Web浏览器中显示PDF文档。PDF.js支持懒加载&#xff0c;也就是说&#xff0c;它可以在用户滚动页面时才加载PDF文档的某些部分&#xff0c;从而减少初始加载时间和内存占用。 注意点&#xff1a;如果要运行在多留…...

K8s 多租户方案的挑战与价值

在当今企业环境中&#xff0c;随着业务的快速增长和多样化&#xff0c;服务器和云资源的管理会越来越让人头疼。K8s 虽然很强大&#xff0c;但在处理多个部门或团队的业务部署需求时&#xff0c;如果缺乏有效的多租户支持&#xff0c;在效率和资源管理方面都会不尽如人意。 本…...

单链表相关经典算法OJ题:移除链表元素

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 前言 题目&#xff1a;移除链表元素 解法一&#xff1a; 解法一的代码实现&#xff1a; 解法二&#xff1a; 解法二代码的实现&#xff1a; 总结 前言 世上有两种耀眼的…...

【JUC】十九、volatile与内存屏障

文章目录 1、volatile的两大特性2、volatile的四大内存屏障3、分类4、happens-before之volatile变量重排规则5、读写屏障插入策略 1、volatile的两大特性 被volatile修饰的变量有两大特点&#xff1a; 可见性有序性 关于volatile的可见性&#xff0c;也即volatile的内存语义…...

下载MySQL JDBC驱动的方法

说明 java代码通过JDBC访问MySQL数据库&#xff0c;需要MySQL JDBC驱动。 例如&#xff0c;下面这段代码&#xff0c;因为找不到JDBC驱动&#xff0c;所以执行会报异常&#xff1a; package com.thb;public class JDBCDemo {public static void main(String[] args) throws …...

C/C++ 实现FTP文件上传下载

FTP&#xff08;文件传输协议&#xff09;是一种用于在网络上传输文件的标准协议。它属于因特网标准化的协议族之一&#xff0c;为文件的上传、下载和文件管理提供了一种标准化的方法&#xff0c;在Windows系统中操作FTP上传下载可以使用WinINet库&#xff0c;WinINet&#xff…...

第十三章 python之爬虫

Python基础、函数、模块、面向对象、网络和并发编程、数据库和缓存、 前端、django、Flask、tornado、api、git、爬虫、算法和数据结构、Linux、设计题、客观题、其他 第十三章 爬虫 1. 写出在网络爬取过程中, 遇到防爬问题的解决办法。 在网络爬取过程中&#xff0c;可能会遇…...

scrum 敏捷开发

scrum 敏捷开发 Scrum 是一种敏捷软件开发方法&#xff0c;旨在通过迭代、增量和协作的方式提高团队的效率和产品质量。下面是关于 Scrum 的一些重要概念和实践&#xff1a; 1. Scrum 团队角色 Scrum 团队通常由以下角色组成&#xff1a; 产品负责人&#xff08;Product Ow…...

亚信科技AntDB数据库完成中国信通院数据库迁移工具专项测试

近日&#xff0c;在中国信通院“可信数据库”数据库迁移工具专项测试中&#xff0c;湖南亚信安慧科技有限公司&#xff08;简称&#xff1a;亚信安慧科技&#xff09;数据库数据同步平台V2.1产品依据《数据库迁移工具能力要求》、结合亚信科技AntDB分布式关系型数据库产品&…...

深度学习(一):Pytorch之YOLOv8目标检测

1.YOLOv8 2.模型详解 2.1模型结构设计 和YOLOv5对比&#xff1a; 主要的模块&#xff1a; ConvSPPFBottleneckConcatUpsampleC2f Backbone ----->Neck------>head Backdone 1.第一个卷积层的 kernel 从 6x6 变成了 3x3 2. 所有的 C3 模块换成 C2f&#xff0c;可以发现…...

EasyExcel如何读取全部Sheet页数据方法

一、需求描述 Excel表格里面大约有20个sheet页&#xff0c;每个sheet页65535条数据&#xff0c;需要读取全部数据&#xff0c;并导入至数据库。 找了好多种方式&#xff0c;EasyExcel比较符合&#xff0c;下面看代码。 二、实现方式 采用EasyExcel框架的doReadAll()方法 1、…...

GDPU 数据结构 天码行空12

文章目录 数据结构实验十二 图的遍历及应用一、【实验目的】二、【实验内容】三、实验源代码&#x1f37b; CPP&#x1f37b; C 数据结构实验十二 图的遍历及应用 一、【实验目的】 1、 理解图的存储结构与基本操作&#xff1b; 2、熟悉图的深度度优先遍历和广度优先遍历算法…...

什么是 Proxy?

目录 Proxy 的作用 1. 流量过滤 2. 记录日志 3. 加快访问速度 4. 隐藏 IP 地址 Proxy 的分类 1. 按协议分类 - HTTP 代理&#xff1a;只支持 HTTP 协议的代理服务器&#xff0c;它可以缓存 HTTP 请求和响应并过滤 HTTP 流量。 - FTP 代理&#xff1a;只支持 FTP 协议的…...

Vue系列:Vue Element UI中,使用按钮实现视频的播放、停止、停止后继续播放、播放完成后重新播放功能

最近在工作中有个政务大屏用到了视频播放&#xff1b; 技术栈是Vue2、Element UI&#xff1b; 要实现的功能是&#xff1a;使用按钮实现视频的播放、停止、停止后继续播放、播放完成后重新播放功能 具体可以按照以下步骤进行操作&#xff1a; 引入插件&#xff1a; 在Vue组件…...