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

news2024/11/26 12:36:13

使用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;
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

手动仿射变换

开发环境&#xff1a; Windows 11 家庭中文版Microsoft Visual Studio Community 2019VTK-9.3.0.rc0vtk-example参考代码目的&#xff1a;学习与总结 demo解决问题&#xff1a;通过仿射控件vtkAffineWidget对目标actor进行手动的拖拽的仿射变换 关键类&#xff1a;vtkAffineWi…

PostGIS轨迹分析——简化轨迹

需求 对轨迹线进行简化,并将原始轨迹上的两个特征点拉取到简化后的轨迹上 简化线 红色线是简化后的轨迹线,蓝色线是原始轨迹,有两个特征点 知识点: st_makeline函数将点连成线st_simplify简化线函数,其中第二个参数为坐标系的单位,0.002度大概代表0.002x1.11x10^5≈22…

使用 ElementUI 组件构建 Window 桌面应用探索与实践(WinForm)

零、实现原理与应用案例设计 1、原理 基础实例 Demo 可以参照以下这篇博文&#xff0c; 基于.Net CEF 实现 Vue 等前端技术栈构建 Windows 窗体应用-CSDN博客文章浏览阅读291次。基于 .Net CEF 库&#xff0c;能够使用 Vue 等前端技术栈构建 Windows 窗体应用https://blog.c…

通过xshell传输文件到服务器

一、user is not in the sudoers file. This incident will be reported. 参考链接&#xff1a; [已解决]user is not in the sudoers file. This incident will be reported.(简单不容易出错的方式)-CSDN博客 简单解释下就是&#xff1a; 0、你的root需要设置好密码 sudo …

java 申请堆外内存吗? java如何使用堆外内存?

java 申请堆外内存吗&#xff1f; java如何使用堆外内存&#xff1f; Java堆外内存管理 JVM可以使用的内存分外2种&#xff1a;堆内存和堆外内存&#xff1a; 堆内存完全由JVM负责分配和释放&#xff0c;如果程序没有缺陷代码导致内存泄露&#xff0c;那么就不会遇到java.lan…

【DriveGPT学习笔记】自动驾驶汽车Autonomous Vehicle Planning

原文地址&#xff1a;DriveGPT - Lei Maos Log Book 自动驾驶汽车的核心软件组件是感知、规划和控制。规划是指在给定场景或一系列场景的情况下为自动驾驶汽车制定行动计划的过程&#xff0c;以实现安全和理想的自动驾驶。 用于规划的场景是从感知软件组件获得的。计划的行动将…

Node学习笔记之跨域

1.跨域是什么&#xff1f; 跨域&#xff0c;是指浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的&#xff0c;是浏览器对JavaScript实施的安全限制。 同源策略限制了一下行为&#xff1a; Cookie无法读取DOM 和 JS 对象无法获取Ajax请求发送不出去 同源是指&#…

如何通过 NAT 模式连接VMware虚拟机以及存在和不存在ens33文件的解决方案

文章目录 前言1 VMware配置1.1 打开vmvare虚拟网络编辑器1.2 取消使用本地DHCP1.3 NAT设置 2 虚拟机的配置2.1 存在ens332.2.1 修改ifcfg-ens33文件2.2.1.1 为什么设置BOOTPROTOstatic&#xff1f;2.2.1.2 如何选择使用static还是dhcp&#xff1f; 2.2.2 关闭防火墙 2.2 不存在…

王道p18 3.对长度为n的顺序表L,编写一个时间复杂度为 O(n)、空间复杂度为 O(1)的算法,该算法删除线性表中所有值为x的数据元素。(c语言代码实现)

视频讲解在这里&#xff08;谢谢各位大佬&#xff09; &#x1f447; p18 第三题数据结构课后算法题_哔哩哔哩_bilibili 本题代码如下 void deletex(struct sqlist* s, int x) {int k 0;int i 0;for (i 0; i < s->length; i){if (s->a[i] ! x)//只要不等于x&…

rcore 笔记 批处理系统 邓氏鱼

批处理系统 批处理系统 (Batch System) &#xff0c;它可用来管理无需或仅需少量用户交互即可运行的程序&#xff0c;在资源允许的情况下它可以自动安排程序的执行&#xff0c;这被称为“批处理作业”。 特权机制 实现特权级机制的根本原因是应用程序运行的安全性不可充分信…

Linux-----nginx的简介,nginx搭载负载均衡以及nginx部署前后端分离项目

目录 nginx的简介 是什么 nginx的特点以及功能 Nginx负载均衡 下载 安装 负载均衡 nginx的简介 是什么 Nginx是一个高性能的开源Web服务器和反向代理服务器。它的设计目标是为了解决C10k问题&#xff0c;即在同一时间内支持上万个并发连接。 Nginx采用事件驱动的异…

基于nodejs+vue啄木鸟便民维修网站设计与实现

目 录 摘 要 I ABSTRACT II 目 录 II 第1章 绪论 1 1.1背景及意义 1 1.2 国内外研究概况 1 1.3 研究的内容 1 第2章 相关技术 3 2.1 nodejs简介 4 2.2 express框架介绍 6 2.4 MySQL数据库 4 第3章 系统分析 5 3.1 需求分析 5 3.2 系统可行性分析 5 3.2.1技术可行性&#xff1a;…

树结构及其算法-二叉树节点的删除

目录 树结构及其算法-二叉树节点的删除 C代码 树结构及其算法-二叉树节点的删除 二叉树节点的删除操作稍为复杂&#xff0c;可分为以下3种情况。 删除的节点为树叶&#xff0c;只要将其相连的父节点指向NULL即可。删除的节点只有一棵子树。删除的节点有两棵子树。要删除节点…

Mysql高级操作和六大约束

一.数据库高级操作 1.1.克隆表 &#xff08;1&#xff09;克隆表&#xff0c;将数据表的数据记录生成到新的表中 方法一&#xff1a; create table test01 like KY08; #通过LIKE方法&#xff0c;复制KY08表结构生成test01 表 insert into test01 select * from KY08; #此方法…

分布式事务(再深入)——分布式事务理论基础 Java分布式事务解决方案

前言 事务(TRANSACTION)是一个不可分割的逻辑单元&#xff0c;包含了一组数据库操作命令&#xff0c;并且把所有的命令作为一个整体向系统提交&#xff0c;要么都执行、要么都不执行。 事务作为系统中必须考虑的问题&#xff0c;无论是在单体项目还是在分布式项目中都需要进行…

HAL服务整编错误处理

HAL服务整编错误处理 1、HIDL HAL服务2、HIDL HAL服务集成1》manifest.xml 配置报错2》hidl服务未启动报错3》有rc启动文件&#xff0c;没有so库报错4》SELinux权限问题5》整编译还是没有集成 或 报错 1、HIDL HAL服务 请参考下面几篇&#xff1a; 简单HIDL HAL的实现 Android系…

Ubuntu18.04LTS上安装ROS melodic

目录 前言创建source.list安装curl通过curl获取PGP公钥更新系统软件包索引安装ROS激活ROS系统空间 前言 本文参考ROS官方wiki&#xff0c;描述在Ubuntu18.04LTS上安装ROS的过程。 创建source.list sudo sh -c echo "deb http://packages.ros.org/ros/ubuntu $(lsb_rele…

「更新」Macos屏幕录像工具:ScreenFlow

mac电脑屏幕截图工具哪个好&#xff1f;ScreenFlow是Mac上的一款优秀的屏幕录像软件&#xff0c;它不仅具有屏幕录制功能&#xff0c;还具有视频编辑功能。以下是对ScreenFlow的一些详细介绍&#xff1a; 首先&#xff0c;ScreenFlow可以捕获摄像机、麦克风和计算机音频&#…

一段奇葩的1024代码

入门教程、案例源码、学习资料、读者群 请访问&#xff1a; python666.cn 大家好&#xff0c;欢迎来到 Crossin的编程教室 &#xff01; 10月24号那天&#xff0c;也就是传说中的1024程序员节&#xff0c;我翻开日历的时候&#xff0c;看到一段代码&#xff1a; 说实话&#xf…

CPU就绪情况及其对虚拟机性能的影响

CPU就绪是虚拟化中的一种性能度量&#xff0c;用于指示物理CPU中的潜在问题&#xff0c;作为对系统效率的度量&#xff0c;它用于跟踪性能和资源利用率&#xff0c;并避免严重错误。为了理解它在管理虚拟机中的重要性&#xff0c;我们将探讨CPU就绪作为一种性能指标的作用。 让…