C++使用栈实现简易计算器(支持括号)

使用C++实现,使用系统自带stac

  1. 支持括号处理
  2. 支持小数计算
  3. 支持表达式有效性检查
  4. 支持多轮输入。

运行结果示例:

代码:

#include <iostream>
#include <stack>
#include <string>
using namespace std;


//判断是否是数字字符
int isNumber(char c)
{
	if(c>='0' && c<='9')
		return 1;
	else
		return 0;
}

//判断字符是否是操作符,这里仅支持+、-、*、/
int isOperator(char c)
{
	if(c=='+' || c=='-' || c=='*' || c=='/')
		return 1;
	else
		return 0;
}

//获取操作符的优先级
int priority(char op)
{
	if(op=='+' || op=='-')
		return 1;
	else if(op=='*' || op=='/')
		return 2;
	else if(op=='(')
		return 0;
	return 0;
}


//有效性判断1:判断是否缺操作符,缺操作符返回1,否则返回0
int isLessOperator(char* p)
{
	int i = 0,j,k;
	//考虑一下几种情况:
	//1.数字之间没有操作符,例如 2 3 + 4
	//2.(前面是数字,例如 2(2+3),这里不支持省略乘号
	//3.)后面是数字,例如 (2+3)3,这里不支持省略乘号
	while(p[i]!='\0')
	{
		if(p[i]==' ')
		{
			j = i-1; 
			while(j>=0 && p[j]==' ') j--; //往前遍历,直到遇到非空格
			k = i+1;
			while(p[k]==' ') k++;//往后遍历,直到遇到非空格
			if(j>=0 && isNumber(p[j]) && isNumber(p[k])) //空格前后都是数字
				return 1; //说明缺少操作符,返回1
		}
		else if(p[i]=='(')
		{
			j = i-1;
			while(j>=0)
			{
				if(isOperator(p[j]) || p[j]=='(')
					break;
				else if(p[j]==' ')//跳过空格
				{
					j--;
					continue;
				}
				else if(isNumber(p[j]))
					return 1;
				else if(p[j]==')')//出现 )(这种情况,((这种情况在这里不讨论,会在括号匹配函数中处理
					return 1; 
				else
					return 2; //这里可能出现非数字、非操作符、非括号
			}
		}else if(p[i]==')')
		{
			j = i+1;
			while(p[j]!='\0')
			{
				if(isNumber(p[j]))
					return 1;
				else if(isOperator(p[j]))
					break;
				else if(p[j]==' ')
				{
					j++;
					continue;
				}
				else if(p[j]==')')
					break;
				else if(p[j]=='(')
					return 1;
				else
					return 2; //出现非数字、非操作符、非括号
			}
		}
		i++;
	}

	return 0;
}
//有效性判断2:判断括号是否匹配,匹配返回1,否则返回0
int isComplete(char* p)
{
	int i=0;
	int nmb = 0; //(的个数
	while(p[i]!='\0')
	{
		if(p[i]=='(')
			nmb++;
		else if(p[i]==')')
			nmb--;
		if(nmb<0)
			return 0;
		i++;
	}
	if(nmb != 0)
		return 0;
	return 1;
}
//有效性判断3:是否是连续操作符(负数操作时必须用括号括起来),出现连续操作符返回1,否则返回0
int isMoreOperator(char* p)
{
	int i=0,j;
	while(p[i]!='\0')
	{
		if(isOperator(p[i]))
		{
			j=i-1; //向前判断
			while(j>=0)
			{
				if(p[j]==' ')
				{
					j++;
					continue;
				}else if(isOperator(p[j]))
					return 1;
				else if(isNumber(p[j]))
					break;
				else if(p[j]==')'||p[j]=='(') //是括号
					break;
				else
					return 2; //非数字、非空格、非括号、非操作符外的其他符号
			}
		}
		i++;
	}
	return 0; //
}


//有效性判断4:判断是否是空括号,如2+()+3
int isEmptyKh(char* p)
{
	int i=0,j;
	while(p[i]!='\0')
	{
		if(p[i]==')')
		{
			j= i-1;
			while(j>=0)
			{
				if(p[j]=='(')
					return 1;
				else if(p[j]==' ')
					j--;
				else
					break;
			}
		}
		i++;
	}
	return 0;
}
//判断表达式的有效性
int isValid(char* p)
{
	int res = 1,t;
	int len = strlen(p);
	if(p[len-1]=='=' || p[len-1]=='#') //以=或者#结尾
		p[len-1]=0;
	t = isLessOperator(p);
	if(t == 1)
	{
		printf("缺少操作符!\n");
		res = 0;
	}else if(t == 2)
	{
		printf("出现符数字、空格、操作符、括号之外的符号\n");
		res = 0;
	}
	t = isComplete(p);
	if(t==0)
	{
		printf("括号不匹配\n");
		res = 0;
	}
	t = isMoreOperator(p);
	if(t == 1)
	{
		printf("有多个连续运算符\n");
		res = 0;
	}else if(t==2)
	{
		printf("出现符数字、空格、操作符、括号之外的符号\n");
		res = 0;
	}

	t = isEmptyKh(p);
	if(t==1)
	{
		printf("有空括号\n");
		res = 0;
	}
	return res;
}
//执行某个运算
int getResult(double a,double b,char c,double *v)
{
	if(c=='+')
	{
		*v = a+b;
		return 1;
	}else if(c=='-')
	{
		*v = a-b;
		return 1;
	}else if(c=='*')
	{
		*v = a*b;
		return 1;
	}else if(c=='/')
	{
		if(b==0)
			return 0;
		*v = a/b;
		return 1;
	}
	return 0;
}
//计算
int Caculate(char* p,double *res)
{
	stack<double> data; //数据
	stack<char> oper;  //操作符
	int i=0;
	double a,b,c;
	char op1,op2;
	double mi=1; 
	while(p[i]!='\0')
	{
		if(isNumber(p[i])) //当前字符是数字,则读取后续的数字,并入栈
		{
			a = p[i]-'0';
			i++;
			//继续读取后面的数字
			while(isNumber(p[i]))
			{
				a = a*10+(p[i]-'0');
				i++;
			}
			if(p[i]=='.')
			{
				i++;
				//处理小数部分
				mi = 10;
				while(isNumber(p[i]))
				{
					a = a + (p[i]-'0')/mi;
					mi*=10;
					i++;
				}
			}
			data.push(a);//数据入栈

		}else if(isOperator(p[i])) //是运算符
		{
			if(oper.empty())
			{
				oper.push(p[i]);
				i++;
			}else
			{
				op1 = oper.top(); //获取栈顶运算符
				//比较op1和p[i]的优先级,如果op1的优先级高于p[i],则数据出栈并进行计算
				if(priority(op1) >= priority(p[i]))
				{
					b = data.top(); //后操作数
					data.pop();
					a = data.top(); //前操作数
					data.pop();
					oper.pop(); //运算符出栈
					if(getResult(a,b,op1,&c))
					{
						if(!oper.empty())
						{
							op2 = oper.top();
							if(op2=='-' && c<0)
							{
								oper.pop();
								oper.push('+');
								data.push(-c); //减负数等价于加正数
								oper.push(p[i]);
							}else
							{
								data.push(c); //新数据入栈
								oper.push(p[i]); //操作符入栈
							}
						}else
						{
							data.push(c); //新数据入栈
							oper.push(p[i]); //操作符入栈
						}

						i++;
					}else
					{
						printf("除数为0\n");
						return 0;
					}
				}else
				{
					oper.push(p[i]); //操作符入栈
					i++;
				}
			}

		}else if(p[i]=='(')
		{
			oper.push(p[i]); //入栈
			i++;
		}else if(p[i]==')') //出栈计算
		{
			op1 = oper.top();
			if(op1=='(')
			{
				oper.pop();//(出栈
				i++;
			}else 
			{
				b = data.top(); //获取栈顶元素,该数为后操作数
				data.pop();
				a = data.top();
				data.pop();
				oper.pop(); //运算符出栈
				if(getResult(a,b,op1,&c))
				{
					if(!oper.empty())
					{
						op2 = oper.top();
						if(op2=='-' && c< 0)
						{
							oper.pop();
							oper.push('+');
							data.push(-c);
						}else
							data.push(c);
					}else
						data.push(c);//新数据入栈

				}else
				{
					printf("除数为0\n");
					return 0;
				}
			}
		} else if(p[i]==' ')
			i++;
	}
	//处理栈内数据
	while(!oper.empty())
	{
		b = data.top();
		data.pop();
		a = data.top();
		data.pop();
		op1 = oper.top();
		oper.pop();
		if(getResult(a,b,op1,&c))
		{
			if(!oper.empty())
			{
				op2 = oper.top();
				if(op2 == '-' && c< 0)
				{
					oper.pop();
					oper.push('+');
					data.push(-c);
				}else
					data.push(c);
			}else
				data.push(c);
		}else
		{
			printf("除数为0\n");
			return 0;
		}
	}
	if(data.size() !=1 )
	{
		printf("error\n");
		return 0;
	}
	*res = data.top();
	data.pop();
	return 1;
}

int main()
{
	char buf[100]={0};
	int op;
	while(1)
	{
		printf("输入表达式:\n");
		cin.getline(buf,100); //读取一行
		double res = 0;
		if(isValid(buf))
		{
			if(Caculate(buf,&res))
				printf("%g\n",res);
		}
		printf("是否继续(1:继续   2:退出):");
		scanf("%d",&op);
		if(op == 2)
			break;
		getchar(); //吸收回车符
	}
	
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/112802.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于MFC的串口通信(Mscomm)

1、串口通信的概述&#xff1a; 串口是一种重要的通信资源&#xff0c;例如鼠标口、USB接口都是串口。串行端口是CPU和串行设备间的编码转换器。当数据从CPU经过端口发送出去的时候&#xff0c;字节数据会被转为串行的位&#xff0c;在接收数据时&#xff0c;串行的位被转换为…

k8s调度约束

List-Watch Kubernetes 是通过 List-Watch的机制进行每个组件的协作&#xff0c;保持数据同步的&#xff0c;每个组件之间的设计实现了解耦。 List-Watch机制 工作机制&#xff1a;用户通过 kubectl请求给 APIServer 来建立一个 Pod。APIServer会将Pod相关元信息存入 etcd 中…

【ROS系列】坐标系转换介绍和对齐

一、坐标系简介 本篇文章介绍&#xff1a;ECEF、ENU、UTM、WGS-84坐标系&#xff08;LLA) 1.1、ECEF坐标系 ECEF坐标系也叫地心地固直角坐标系。 原点&#xff1a;地球的质心&#xff0c; x轴&#xff1a;原点延伸通过本初子午线&#xff08;0度经度&#xff09;和赤道&am…

京东数据分析:2023年9月京东洗地机行业品牌销售排行榜

鲸参谋监测的京东平台9月份洗地机市场销售数据已出炉&#xff01; 9月份&#xff0c;洗地机市场的销售额增长。根据鲸参谋电商数据分析平台的相关数据显示&#xff0c;9月京东平台上洗地机的销量为9.2万&#xff0c;销售额将近2.2亿&#xff0c;同比增长约9%。从价格上看&#…

爬虫 | 【实践】百度搜索链接爬取,生成标题词云 | 以“AI换脸”为例

目录 &#x1f4da;链接爬取 &#x1f407;流程梳理 &#x1f407;代码实现 &#x1f407;结果 &#x1f4da;词云生成 &#x1f407;代码实现 &#x1f407;结果 &#x1f4da;链接爬取 &#x1f407;流程梳理 总体流程是&#xff1a;构建搜索链接 -> 发送HTTP请求…

大坝水库安全监测终端MCU,智能化管理的新篇章!

我国目前拥有超过9.8万座水库大坝&#xff0c;其中超过95%为土石坝&#xff0c;这些大坝主要是在上世纪80年代以前建造的。这些水库大坝在保障防洪、发电、供水、灌溉等方面发挥了巨大的作用&#xff0c;但是同时也存在一定的安全风险&#xff0c;比如坝体结构破损、坝基渗漏、…

当你在浏览器地址栏输入一个URL后,将会发生的事情?个人笔记

客户端 在浏览器输入 URL 回车之后发生了什么&#xff08;超详细版&#xff09; - 知乎 (zhihu.com) 大致流程是&#xff1a; URL 解析DNS 查询TCP 连接处理请求接受响应渲染页面 1.URL解析 地址解析&#xff1a; 首先判断你输入是否是一个合法的URL还是一个待搜索的关键…

【C++】set和multiset

文章目录 关联式容器键值对一、set介绍二、set的使用multiset 关联式容器 STL中的部分容器&#xff0c;比如&#xff1a;vector、list、deque、forward_list(C11)等&#xff0c;这些容器统称为序列式容器&#xff0c;因为其底层为线性序列的数据结构&#xff0c;里面存储的是元…

从内存管理的角度来看,Python语言的变量和参数传递情况解析

从内存管理的角度来看&#xff0c;Python语言的变量和参数传递情况解析 概述 从内存管理的角度来看&#xff0c;Python中的变量和参数传递有一些特点&#xff1a; ☆ 变量是对象的引用&#xff1a;在Python中&#xff0c;变量实际上是对象的引用&#xff0c;而不是对象本身。…

vi vim 末尾编辑按GA 在最后一行下方新增一行编辑按Go

vim 快速跳到文件末尾 在最后一行下方新增一行 移到末尾,并且进入文本录入模式 GA (大写G大写A) 在一般模式(刚进入的模式,esc模式) GA 或 Shift ga 先 G 或 shiftg 到最后一行 然后 A 或 shifta 到本行末尾 并且进入文本录入模式 在最后一行下方新增一行 (光标换行,文字不…

【Linux】Nginx安装使用负载均衡及动静分离(前后端项目部署),前端项目打包

一、Nginx导言 1、引言 Nginx 是一款高性能的 Web 服务器和反向代理服务器&#xff0c;也可以充当负载均衡器、HTTP 缓存和安全防护设备。它的特点是内存占用小、稳定性高、并发性强、易于扩展&#xff0c;因此在互联网领域得到了广泛的使用。 总结出以下三点: 负载均衡&#x…

lvsDR模式

LVS-DR模式 是最常用的LVS负载方式 直接路由模式 Lvs调度器 只负责请求和转发 转发到真实服务器 但是响应结果 由后端服务器直接转发给客户端 不需要经过调度器处理 可以减轻Lvs调度器的负担 提高系统性能和稳定性 工作原理&#xff1a; 客户端发送请求到vipLVS调度器接受请求…

miniconda快速安装

目录 一、Linux下miniconda安装 1.1、安装 1.2、miniconda初始化 二、Windows下miniconda安装 三、maOS下miniconda安装 3.1、安装 3.2、miniconda初始化 四、参考&#xff1a; 本文给出windows、macos、linux下快速安装miniconda方法。 对比conda&#xff0c;minicond…

光学仿真|优化汽车内部照明体验

当我们谈论优化人类感知的内部照明时&#xff0c;我们实际上指的是两个重点领域&#xff1a;安全性和驾驶员体验。如果内部照明可以提供尽可能最佳的体验&#xff0c;驾驶员则能够更好地应对颇具挑战性或意外的驾驶状况&#xff0c;并且减轻疲劳感。除了功能优势外&#xff0c;…

【Servlet】 一

本文主要介绍了如何在tomcat部署一个webapp 以及 如何借助maven用servlet编写一个hello world . 一.Tomcat Tomcat是一个Java里广泛使用的http服务器 HTTP服务器有很多实现&#xff0c;其中最知名的是Nginx&#xff1b;而在Java里&#xff0c;最知名的是Tomcat 一个Tomcat服务…

【K8S】二进制安装

常见的K8S安装部署方式 ●Minikube Minikube是一个工具&#xff0c;可以在本地快速运行一个单节点微型K8S&#xff0c;仅用于学习、预览K8S的一些特性使用。 部署地址&#xff1a;https://kubernetes.io/docs/setup/minikube ●Kubeadm☆ Kubeadm也是一个工具&#xff0c;提…

LInux之在同一Tomcat下使用不同的端口号访问不同的项目

&#x1f389;&#x1f389;欢迎来到我的CSDN主页&#xff01;&#x1f389;&#x1f389; &#x1f3c5;我是君易--鑨&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; &#x1f31f;推荐给大家我的博客专栏《LInux实战开发》。&#x1f3af;&#x1f3af; …

Vue入门——核心知识点

简介 Vue是一套用于构建用户界面的渐进式JS框架。 构建用户界面&#xff1a;就是将后端返回来的数据以不同的形式(例如&#xff1a;列表、按钮等)显示在界面上。渐进式&#xff1a;就是可以按需加载各种库。简单的应用只需要一个核心库即可&#xff0c;复杂的应用可以按照需求…

transformers-AutoClass

https://huggingface.co/docs/transformers/main/en/autoclass_tutorialhttps://huggingface.co/docs/transformers/main/en/autoclass_tutorialAutoClass可以自动推断和加载给定checkpoint的正确架构。 对于文本&#xff0c;使用Tokenizer将文本转换为token序列&#xff0c;创…

IDEA中application.properties文件中文乱码

现象&#xff1a; 原因&#xff1a; 项目编码格式与IDEA编码格式不一致导致的 解决办法&#xff1a; 在File->Settings->Editor->File Encodings选项中&#xff0c;将Global Encoding,Project Encoding,Default encoding for properties files这三个选项置为一致&a…