说实话 我之前写过别的类型的计算器
基于lisp语言的那种 这种通用的没写过 但是因为要带几个C++新手入门
考虑再三 感觉还是计算器比较可行 作为入门的话 不会太难 也不太简单
既然是基础入门 计算思路就比较简单 (太复杂的我也不会哈,至少需要查书了)
加减乘除、多层括号、n次方混合运算
下面贴代码
// Calculator.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
#include <vector>
#include <string>
//#define DEBUG
using namespace std;
class CalElement
{
public:
bool IsValue;//true=value false=operat
union
{
int operat;
double value;
}body;
//存粹是为了让新手看一下union……这个例子里面内存节省基本上是0
//主要是能放在一个结构体里面方便后面使用
public:
void SetValue(double src)
{
IsValue = true;
body.value = src;
}
void SetOperat(int src)
{
IsValue = false;
body.operat = src;
}
bool GetData(int &operat_o, double &value_o)
//留意一下这种传参方式 C++ (&) C#(ref)都有
{
if (IsValue) { value_o = body.value; }
else { operat_o = body.operat; }
return IsValue;
}
};
bool IsValue(char src)
{
if ((src >= 48 && src <= 57) || src == 46)
{
return true;
}
return false;
}
int GetOperaValue(string src, int &count)
{
count = 1;
switch (src[0])
{
case 43:return 1; break;// +
case 45:return 2; break;// -
case 42:return 3; break;// *
case 47:return 4; break;// /
case 40:return 5; break;// (
case 41:return 6; break;// )
case 94:return 7; break;// ^
//目前这个版本还没支持xy变量,不过应该很好加
case 120:return 20; break;// x
case 88:return 20; break;// X
case 121:return 21; break;// y
case 89:return 21; break;// Y
}
if (src == "exp")
{
count = 3;
return 100;
}
else if (src == "exp(")
{
count = 4;
return 101;
}
else
{
count = 0;
return -1;
}
}
double getValue(string src, int index, int &count)//字符串转double
{
string temp;
count = 0;
for (int i = index; i < src.length(); i++)
{
if (IsValue(src[i]))
{
temp = temp + src[i];
}
else
{
break;
}
}
count = temp.length();
if (count == 0)
{
count = 1;
return 0;
}
return stod(temp);
}
int getOperat(string src, int index, int &count)//获得操作符
{
string temp;
count = 0;
for (int i = index; i < src.length(); i++)
{
if (IsValue(src[i]))break;
temp = temp + src[i];
}
int t = GetOperaValue(temp, count);
return t;
}
//按照操作符和数字将输入的字符串给切开 注意传参时候的引用 &
void PreSeprate(string srcStr,vector<CalElement> &calStr)
{
int i;
int count = 0;
int tempOperat;
for (i = 0; i < srcStr.size();)
{
i = i + count;
tempOperat = getOperat(srcStr, i, count);
if (tempOperat == -1)
{
CalElement temp;
temp.SetValue(getValue(srcStr, i, count));
calStr.push_back(temp);
}
else
{
CalElement temp;
temp.SetOperat(tempOperat);
calStr.push_back(temp);
}
}
}
//将括号在新的数组里面标示出来,一方面计算括号层数,一方面可以进行括号的预分割
vector<int>GetBrackets(vector<CalElement>src, int &count)
{
count = 0;
vector<int>state;
int t = 0;
for (int i = 0; i < src.size(); i++)
{
if (!src[i].IsValue)
{
if (src[i].body.operat == 5)
{
t++;
if (t > count) { count = t; }
state.push_back(t);
}
else if (src[i].body.operat == 6)
{
t--;
state.push_back(t);
}
else { state.push_back(t); }
}
else { state.push_back(t); }
}
return state;
}
double SampleCalculate(vector<CalElement>cal)
//没有括号的基本计算
//这里面的vector insert我用的貌似很挫,感冒中,不想了。有人会的话在留言里教我一下
{
CalElement tempElement;
double temp;
//符号首位
if (!cal[0].IsValue)
{
if (cal[0].body.operat == 2)
{
temp = cal[1].body.value *(-1);
//CalElement tempElement;
tempElement.SetValue(temp);
cal.erase(cal.begin(), cal.begin() + 2);
cal.insert(cal.begin(), tempElement);
}
else if (cal[0].body.operat == 1)
{
cal.erase(cal.begin());
}
}
//幂指数
for (int i = 0; i < cal.size(); i++)
{
if (!cal[i].IsValue && cal[i].body.operat==7)
{
temp = pow(cal[i - 1].body.value, cal[i + 1].body.value);
tempElement.SetValue(temp);
cal.erase(cal.begin() + i - 1, cal.begin() + i + 2);
if (cal.size() == 0) { return temp; }
else if (cal.size() <= i - 1)
{
cal.push_back(tempElement);
}
else { cal.insert(cal.begin() + i - 1, tempElement); }
i--;
}
}
//乘除法
for (int i = 0; i < cal.size(); i++)
{
if (!cal[i].IsValue)
{
switch (cal[i].body.operat)
{
case 3:
temp = cal[i - 1].body.value * cal[i + 1].body.value;
tempElement.SetValue(temp);
cal.erase(cal.begin() + i - 1, cal.begin() + i + 2);
if (cal.size() == 0) { return temp; }
else if (cal.size() <= i - 1)
{
cal.push_back(tempElement);
}
else { cal.insert(cal.begin() + i - 1, tempElement); }
i--;
break;
case 4:
if (cal[i + 1].body.value != 0)
{
temp = cal[i - 1].body.value / cal[i + 1].body.value;
}
else
{
temp = double(LONG_MAX);
}
tempElement.SetValue(temp);
cal.erase(cal.begin() + i - 1, cal.begin() + i + 2);
if (cal.size() == 0) { return temp; }
else if (cal.size() <= i - 1)
{
cal.push_back(tempElement);
}
else { cal.insert(cal.begin() + i - 1, tempElement); }
i--;
break;
}
}
}
//加减法
for (int t = 0; t < cal.size(); t++)
{
if (!cal[t].IsValue)
{
switch (cal[t].body.operat)
{
case 1:
temp = cal[t - 1].body.value + cal[t + 1].body.value;
tempElement.SetValue(temp);
cal.erase(cal.begin() + t - 1, cal.begin() + t + 2);
if (cal.size() == 0) { return temp; }
else if (cal.size() <= t - 1)
{
cal.push_back(tempElement);
}
else { cal.insert(cal.begin() + t - 1, tempElement); }
t--;
break;
case 2:
temp = cal[t - 1].body.value - cal[t + 1].body.value;
tempElement.SetValue(temp);
cal.erase(cal.begin() + t - 1, cal.begin() + t + 2);
if (cal.size() == 0) { return temp; }
else if (cal.size() <= t - 1)
{
cal.push_back(tempElement);
}
else { cal.insert(cal.begin() + t - 1, tempElement); }
t--;
break;
}
}
}
return cal[0].body.value;
}
//总的递归调用的计算函数 说递归效率低的可以把这个按照maxLayer转成循环来写
//懒得动 而且 让新学的同学了解一下递归 毕竟循环(迭代)都是会的不是
double Calculate(vector<CalElement>cal)
{
int maxLayer;
vector<int>Brackets = GetBrackets(cal, maxLayer);
if (maxLayer == 0)
{
return SampleCalculate(cal);
}
else
{
int beginIndex = 0;
int endIndex = 0;
bool find = false;
vector<CalElement>tempSimple;
for (int i = 0; i < Brackets.size(); i++)
{
if (Brackets[i] == maxLayer)
{
if (find) { tempSimple.push_back(cal[i]); }
else { beginIndex = i; }
find = true;
}
if (find && Brackets[i] == maxLayer - 1)
{
endIndex = i;
find = false;
break;
}
}
cal.erase(cal.begin() + beginIndex, cal.begin() + endIndex + 1);
CalElement tempElement;
tempElement.SetValue(Calculate(tempSimple));
if (cal.size() < beginIndex)
{
cal.push_back(tempElement);
}
else { cal.insert(cal.begin() + beginIndex, tempElement); }
return Calculate(cal);//递归调用
}
}
//主函数调用
int main()
{
//输入
string srcStr;
std::cin >> srcStr;
//预处理
vector<CalElement>calStr;
PreSeprate(srcStr, calStr);
//计算并输出
cout << Calculate(calStr) << endl;
cin >> srcStr;
return 0;
}
其实回想一下流程很简单的,对吧。
有兴趣的可以把xy变量加进去。