C++制作简易计算器

news2024/7/2 3:53:13

C++简易计算器

C++简易计算器栈栈(Stack)的特点栈的相关概念栈的常用操作为栈的常见分类实例计算器概念代码实现测试

效果展示

简易计算器实现的功能:

基本的加减乘除、表达式错误判断、除法运算分母不能为0、支持多项式表达计算,自己封装一个模板栈、封装计算器的功能,留外部接口getResult().

栈(Stack)的特点

(1)栈中的数据元素遵守“先进后出"(First In Last Out)的原则,简称FILO结构。(后进先出的叫法,也是可以的)

(2)限定只能在栈顶进行插入和删除操作。

栈的相关概念

(1)栈顶与栈底:允许元素插入与删除的一端称为栈顶,另一端称为栈底。

(2)压栈:栈的插入操作,叫做进栈,也称压栈、入栈。

(3)弹栈:栈的删除操作,也叫做出栈。

栈的常用操作为

(1)弹栈,通常命名为pop

(2)压栈,通常命名为push

(3)求栈的大小

(4)判断栈是否为空

(5)获取栈顶元素的值

栈的常见分类

(1)基于数组的栈——以数组为底层数据结构时,通常以数组头为栈底,数组头到数组尾为栈顶的生长方向

(2)基于单链表的栈——以链表为底层的数据结构时,以链表头为栈顶,便于节点的插入与删除,压栈产生的新节点将一直出现在链表的头部

实例

模仿std::stack创建一个模板类

实现栈的基本功能:

public:
	void clear();	//清空数据
	void push(T t);	//入栈
	T pop();		//出栈
	T top();		//获取栈顶元素
public:
	int size();		//栈内元素数量
	bool empty();	//判断栈是否为空

完整代码展示

#pragma once
template<typename T>
struct Node
{
	T m_value;  //储存的值
	Node<T>* pNext;

	Node() :pNext(nullptr){} //构造函数
	Node(T t) :m_value(t), pNext(nullptr) {}
};


template<typename T>
class Stack
{
	int m_length;
	Node<T>* pHead;
public:
	Stack();
	~Stack();
public:
	void clear();	//清空数据
	void push(T t);	//入栈
	T pop();		//出栈
	T top();		//获取栈顶元素
public:
	int size();		//栈内元素数量
	bool empty();	//判断栈是否为空
};

template<typename T>
Stack<T>::Stack()
{
	m_length = 0;
	pHead = new Node<T>;
}

template<typename T>
Stack<T>::~Stack()
{
	clear();
}

template<typename T>
void Stack<T>::clear()
{
	while (pHead->pNext != nullptr)
	{
		Node<T> *temp = pHead->pNext;
		pHead->pNext = temp->pNext;
		delete temp;
	}
}

template<typename T>
void Stack<T>::push(T t)
{
	Node<T> *pNode = new Node<T>(t);	//申请入栈元素的空间
	pNode->pNext = pHead->pNext;
	pHead->pNext = pNode;
	m_length++;
}

template<typename T>
T Stack<T>::pop()
{
	if (pHead->pNext != nullptr)
	{
		Node<T>* temp = pHead->pNext;
		pHead->pNext = temp->pNext;
		T popVal = temp->m_value;
		delete temp;
		m_length--;
		return popVal;
	}
}

template<typename T>
T Stack<T>::top()
{
	if (pHead->pNext != nullptr)
	{
		return pHead->pNext->m_value;
	}
}

template<typename T>
int Stack<T>::size()
{
	return m_length;
}

template<typename T>
bool Stack<T>::empty()
{
	if (pHead->pNext != nullptr)
		returnfalse;
	returntrue;
}

计算器

利用栈实现简易计算器

概念

假设有这样一个表达式

2+3*2+2*(2*2+3)

由于在数学的算式中乘除的优先于加减运算,所以我们必须要把两个相邻的加或减之间的数字或者乘除算式看成一个项,最后再对所有项(term)进行加减操作。为了简单化,这里不考虑计算负数.

上述表达式里面,()里面看成一个项,假设为X;

X里面又分为两个项2*2(假设为X1),X1+3

在()外面3*2是一个项(假设为Y),

2*X又是一个项(假设为Z)

综合起来就是2+Y+Z

怎么判断是一个项呢,左( 到右 )是一个项,

+ - 之前的为一个项,

* / 之前操作数也是* /,则此也为一个项

代码实现

#pragma once
#include "Stack.h"
#include <string>
usingnamespacestd;
class Calc
{
	string str;
	Stack<int> digit;
	Stack<char> op;
public:
	Calc();
	~Calc();
public:
	int getResult(string Str);
private:
	void setStr(string Str);	//设置表达式
	bool isCalc(char ch);		//是否可以计算项
	void Calculation();			//计算
};

 

给外部一个接口,getResult(),其他的内部实现

#include "Calc.h"

Calc::Calc()
{
	digit.clear();
	op.clear();
}

Calc::~Calc()
{
	digit.clear();
	op.clear();
}

int Calc::getResult(string Str)
{
	setStr(Str);
	int temp = 0;
	for (unsignedint i = 0; i < str.length(); i++)
	{
		//判断是否是数字
		if (isdigit(str[i]))
		{
			temp = temp * 10 + str[i] - '0';
			if (i + 1 == str.length() || !isdigit(str[i + 1]))
			{
				digit.push(temp);
				temp = 0;
			}
		}
		//判断是否运算操作符
		elseif (str[i] == '+' || str[i] == '-' || str[i] == '*' || str[i] == '/')
		{
			if (isCalc(str[i]))
				Calculation();
			op.push(str[i]);
		}
		elseif (str[i] == '(') {
			op.push(str[i]);
		}
		elseif (str[i] == ')') {
			while (op.top() != '(')
				Calculation();
			op.pop();	//弹出)
		}
	}
	while (!op.empty())
		Calculation();

	return digit.pop();
}

void Calc::setStr(string Str)
{
	this->str = Str;
	digit.clear();
	op.clear();
}

bool Calc::isCalc(char ch)
{
	if (op.empty())
		returnfalse;
	if (op.top() == '(')	
		returnfalse;
	if (ch == '+' || ch == '-')		//	1*2+5	遇到 + - ,前面一段表达式为一个运算单位
		returntrue;
	if (ch == '*' && (op.top() == '*' || op.top() == '/'))
		returntrue;
	if (ch == '/' && (op.top() == '*' || op.top() == '/'))
		returntrue;
	returnfalse;
}

void Calc::Calculation()
{
	if (!digit.size()) {
		printf("表达式输入错误\n");
		system("pause");
		exit(0);
	}

	int right = digit.pop();

	if (!digit.size()) {
		printf("表达式输入错误\n");
		system("pause");
		exit(0);
	}

	int left = digit.pop();

	int result;
	switch (op.pop())
	{
	case'+':
		result = left + right;
		break;
	case'-':
		result = left - right;
		break;
	case'*':
		result = left * right;
		break;
	case'/':
	{
		//分母不能为0
		if (right == 0) {
			printf("分母不能为0\n");
			system("pause");
			exit(0);
		}
		result = left / right;
	}
		break;
	}
	digit.push(result);
}

测试

#include"Stack.h"
#include"Calc.h"
#include <iostream>
#include<conio.h>
usingnamespacestd;
void introduce();
int main()
{
	string calc_str;
	Calc calc;
	while (1)
	{
		system("cls");
		introduce();
		cin >> calc_str;
		int result = calc.getResult(calc_str);
		cout <<"\t"<<calc_str << "=" << result << endl;
		cout << "\t按任意键返回" << endl;
		getch();
	}
	
	cin.get();
	cin.get();
	return0;
}

void introduce()
{
	printf("\n");
	printf("\t╭  % ╮                   ╭ ```╮  \n");
	printf("\t(@^o^@)   C++简易计算器  (⌒:⌒)\n");
	printf("\t(~):(~)                  (~)v(~) \n");
	printf("\n\n");
	cout << "\t来源:微信公众号【编程学习基地】\n\t作者:梦凡\n" << endl;
	cout << "\t请输入表达式,例如“2+3*2+2*(2*2+3)”:";
}

效果演示:

关于计算器

浮点数参与计算只需要在判断数字那里加上判断小数点的逻辑即可

关于界面:只要支持C++语法,直接将模板栈和类拷贝过去,自己布局一个还算可以的界面,然后再=按钮控件处调用getResult函数将结果显示在lineEdit控件上就可以实现一个简单的计算器。

这个是C++代码,用到了类模板这些C++后面的知识,粉丝大部分也是学完了C++,当然看懂计算过程后C也是类似的实现,类变结构体,Stack<char>可以直接用int类型替换,

 

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

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

相关文章

介绍 9 个研发质量度量指标

研发质量管理中的 MTTR、MTBF、MTTF、MTTD 都是什么&#xff1f;今天我们从生产事件的全生命周期出发&#xff0c;认识研发质量管理的 9 个度量指标——「MT 家族」。 01 Mean Time To ALL 「MT」是 Mean Time 的缩写&#xff0c;意为平均时间&#xff0c;「MT 家族」则是 Li…

OpenStack(T版)——仪表板(Horizon)服务介绍与安装

文章目录 OpenStack(T版)——仪表板(Horizon)服务介绍与安装安装和配置Horizon仪表板服务组件(1)安装软件包(2)修改配置文件(3)修改httpd文件完成安装 访问 OpenStack(T版)——仪表板(Horizon)服务介绍与安装 Openstack项目中的Horrizon仪表板服务组件是以Web界面形式展示各项…

【shell脚本百炼成魔】shell脚本之函数实战

前言 文章目录 前言函数的概念函数的基本语法1.使用关键字 function&#xff1a;2.直接使用函数名和大括号&#xff1a; 函数的简单案例案例一&#xff0c;欢迎函数案例二&#xff1a;购物清单 函数的传参1. 位置参数2. 命令替换3. 数组参数 函数的返回值1. 判断函数的执行结果…

SVNKit 1.10.8: svn add和svn commit方法总结

SVNKit 1.10.8: svn add和svn commit方法实现总结&#xff1a; doAdd(java.io.File path, boolean force, boolean mkdir, boolean climbUnversionedParents, SVNDepth depth, boolean depthIsSticky, boolean includeIgnored, boolean makeParents) 参数是的含义及作用&…

实现淘宝母婴订单实时查询和可视化|Flink-Learning实战营

为进一步帮助开发者学习使用 Flink&#xff0c;Apache Flink 中文社区近期发起 Flink-Learning 实战营项目。本次实战营通过真实有趣的实战场景帮助开发者实操体验 Flink&#xff0c;课程包括实时数据接入、实时数据分析、实时数据应用的场景实。并结合小松鼠助教模式&#xff…

K8s组件:etcd安装、使用及原理(Linux)

K8s组件&#xff1a;etcd安装、使用及原理&#xff08;Linux&#xff09; 1 介绍及安装 1.1 介绍 分布式系统架构中对一致性要求很高&#xff0c;etcd就满足了分布式系统中的一致性要求。 实现了分布式一致性键值对存储的中间件&#xff0c;支持跨平台&#xff0c;有活跃的…

交互式标注工具-Paddlelabel

PaddleLabel 是基于飞桨 PaddlePaddle 各个套件功能提供的配套标注工具。目前支持对分类、检测、分割、OCR 四种常见的计算机视觉任务数据集进行标注和管理&#xff0c;除基础的手动标注功能外也支持深度学习辅助标注&#xff0c;可以有效地提升标注效率。重点是free free free…

玩转代码|那些实用的JavaScript单行代码,帮你轻松工作

目录 数组去重 从url获取参数并转为对象 检查对象是否为空 反转字符串 生成随机十六进制 检查当前选项卡是否在后台 检测元素是否处于焦点 检查设备类型 文字复制到剪贴板 获取选定的文本 查询某天是否为工作日 转换华氏/摄氏 两日期之间相差的天数 将 RGB 转换为…

并发-编程之JMMvolatile详解

并发三大特性&#xff1a;可见性、原子性、有序性 并发都是数据【多线程对一个变量进行连续加1】 线程A和B都对count进行连续加1&#xff0c;因为count不是原子性&#xff0c;如果再执行countcount1之前cpu执行权被抢占&#xff0c;就会阻塞住&#xff0c;这时候线程B完成count…

基于Java车库智能管理平台设计实现(源码+lw+部署文档+讲解等)

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

Java | 使用切面AOP拦截并修改Controller接口请求参数

关注common wx&#xff1a; CodingTechWork 引言 在开发过程中&#xff0c;会有一些需求将controller层的一些方法入参进行全量转换&#xff0c;最容易想到的可能是在调用下层service方法时&#xff0c;调用公共的方法进行入参转换&#xff0c;这时带来的唯一问题就是代码不雅…

TCP的粘包、拆包、解决方案以及Go语言实现

什么是粘包&#xff0c;拆包&#xff1f; TCP的粘包和拆包问题往往出现在基于TCP协议的通讯中&#xff0c;比如RPC框架在使用TCP进行数据传输时&#xff0c;由于TCP是基于字节流的协议&#xff0c;而不是基于消息的协议&#xff0c;可能会出现粘包&#xff08;多个消息粘在一起…

基于matlab创建基于颜色特征的图像检索系统(附源码)

一、前言 此示例说明如何使用自定义的功能包工作流创建基于内容的图像检索 &#xff08;CBIR&#xff09; 系统。 基于内容的图像检索 &#xff08;CBIR&#xff09; 系统用于查找在视觉上与查询图像相似的图像。CBIR系统的应用可以在许多领域找到&#xff0c;例如基于网络的…

记账APP:小哈记账4——记账首页页面的制作(1)

项目介绍&#xff1a; 小哈记账是一款用于记账APP&#xff0c;基于Android Studio开发工具&#xff0c;采用Java语言进行开发&#xff0c;同时使用litepal和阿里云数据库进行数据的增删查改&#xff0c;以图标的形式在App的界面上显示。App可以清晰显示收支情况&#xff0c;并以…

2. MongoDB分片集群架构实战-----MongoDB分片集群和多文档事务详解

分布式技术MongoDB 1. 分片简介2. MongoDB分片集群架构3. 环境搭建3.1 分片集群搭建3.2 使用mtools搭建分片集群 4 使用分片集群5. 分片策略5.1 什么是chunk5.2 分片算法5.3 哈希分片5.4 分片标签5.4 分片键(ShardKey)的选择5.5 分片键(ShardKey)的约束 6. 数据均衡6.1 均衡的方…

【JAVAWEB】JavaScript基础知识

目录 1.认识JavaScript 1.1JavaScript是什么 1.2JavaScript和html,css的关系 1.3JavaScript的组成 2.JavaScript的前置知识 2.1JavaScript的书写形式 行内式 内嵌式 外部式 2.2注释 2.3输入输出 3.JavaScript的语法知识 3.1变量的使用 创建变量 使用变量 3.2动态…

echarts柱状图查找数据

controller层&#xff1a; /*** 查询最近一周每天的行为识别总人数* return*/ApiOperation("查询最近一周每天的行为识别总人数") // RequiresPermissions("zhgd:aialarmdata:selectShu")GetMapping("/selectShu")public List<List> se…

UE5 Motion Warping功能学习

MotionWarping&#xff08;运动扭曲&#xff09;可对角色根运动进行修改&#xff0c;从而让角色根运动动画结束时准确停在某一点&#xff0c;如图&#xff1a; 此外UE5还提供移动步幅、转向的Warping功能&#xff08;防滑步&#xff09;&#xff0c;之前写过一个简单的介绍可…

9.2 IO多路复用select函数

目录 I/O多路复用模型 多路复用的实现方式 select函数 fd_set结构体 I/O多路复用模型 多路复用的实现方式 select函数 int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);poll函数 int poll(struct pollfd *fds, nfds_…

Git 安装 配置初始化

1. Git 下载 1.1 git 官网下载 Git 官网 https://git-scm.com/download/win 根据自己的电脑系统下载对应的版本 1.2 百度网盘下载 百度网盘&#xff1a;https://pan.baidu.com/s/17Thcov7VKfIc_hINcQimrw 提取码&#xff1a;13142. 安装git 2.1 双击安装包 2.2 点击next …