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类型替换,