您的位置:首页 > 其它

四则运算 3

2016-03-19 09:38 369 查看
老师提出了新的要求

1.学生写的程序必须能判定用户的输入答案是否正确

2.程序必须能处理四种运算的混合算式

要求两人合作分析,单独编程,单独撰写博客

团队成员:苗堃、罗毅(http://www.cnblogs.com/ly199553/

设计思路:

查阅了相关资料,发现小学四则运算含有括号数量不多,于是结组讨论时选取了较为简单的我的程序,将数组全部转化为字符串形式,

利用栈实现中缀表达式转换为后缀表达式,转换原则为

1.当读到一个操作数时,立即将它放到输出中。操作符则不立即输出,放入栈中。遇到左圆括号也推入栈中。

2.如果遇到一个右括号,那么就将栈元素弹出,将符号写出直到遇到一个对应的左括号。但是这个左括号只被弹出,并不输出。

3.在读到操作符时,如果此时栈顶操作符优先性大于或等于此操作符,弹出栈顶操作符直到发现优先级更低的元素位置。除了处理')'

的时候,否则决不从栈中移走'('。操作符中,'+' '-'优先级最低,'(' ')'优先级最高。

4.如果读到输入的末尾,将栈元素弹出直到该栈变成空栈,将符号写到输出中。

两位数的字符串传递时加入字符@来区分(/content/4264941.html

输入答案后与正确答案进行比较判断对错

#include<stack>
#include<iostream>
#include<deque>
#include<string>
#include<sstream>
#include<time.h>
using namespace std;

int  Num[100];    //将数字存入数组a
string op_arrays[100];    //将运算符存入数组b
string  All[100];    //合成总数组e
string fu[100];      //辅助数组
int true_num = 0;     //统计做对的题目数
int false_num = 0;    //统计做错的题目数

bool isPra(char);    //判断是否为括号
int getPri(char);    //获得符号优先性
void check(char c, stack<char>& coll2, deque<char>& coll3);//判断符号优先性
void allocate(deque<char>& coll1, stack<char>& coll2, deque<char>& coll3);  //将中缀表达式分解为符号和运算数
void calculate(deque<char>& coll3, stack<double>& coll4);  //计算后缀表达式

int main()
{
srand((int)time(NULL));//设置随机种子,使得程序每次运行的结果都不同
int subject_number;    //出题数量
int random_number = 0;    //运算数字字数
int operation_character = 0;
int fuhao = 0;    //判定运算符

int Jude_has_brackets;       //定义左、右括号的是否存在的随机变量
string left;    //左括号变量
string right;    //左括号变量
string sign = "a";   //定义符号变量
char Jude_has_mul_dev;   //定义是否需要乘除法的变量

deque<char> coll0;  //消除中缀表达式的空格
deque<char> coll1;  //盛放中缀表达式
stack<char> coll2;  //盛放操作符
deque<char> coll3;    //盛放后缀表达式
stack<double>coll4;    //计算后缀表达式的辅助容器

int min, Max;    //定义输入的值得范围的最值(仅能输入整数<=30)
string w = " ";

//写一个简易菜单
cout << "欢       / ̄\_/ ̄\ "<<endl;
cout << "迎      ▏     ▔▔▔▔\    " << endl;
cout << "使     /\ /      ﹨" << endl;
cout << "用   ∕       /   )" << endl;
cout << "小   ▏        ●  ▏"<<endl;
cout << "天   ▏           ▔█ " << endl;
cout << "才  ◢██◣      /\__/" << endl;
cout << "四   █████◣       /" << endl;
cout << "则   █████████████◣ " << endl;
cout << "运 ◢██████████████▆▄" << endl;
cout << "算  █◤◢██◣◥█████████◤\" << endl;
cout << "自 ◥◢████ ████████◤   \" << endl;
cout << "助   █████ ██████◤      ﹨" << endl;
cout << "系  │   │█████◤        ▏" << endl;
cout << "统  │   │            ▏" << endl;
cout << "   ∕   ∕    /▔▔▔\     ∕" << endl;
cout << "  ∕___/﹨   ∕      \  /\" << endl;
cout << "           \    \_     ﹨/  ﹨" << endl;
cout << "             \___\     ﹨/▔\﹨/▔\" << endl;
cout << "                      \   ∕" << endl;
cout << "1.请输入产生数字的范围(最小和最大):";
cin >> min >> Max;
cout << "提示:若您需要做乘除法 请不要做超过30以外的乘除法" << endl;
cout << endl;
cout << "2.是否需要乘除法[y为需要乘除法 n为不需要乘除法] ";
cin >> Jude_has_mul_dev;
while (min<0)
{
cout << "请做正数运算:" << endl;
cout << "输入最小值" << endl;
cin >> min;
}
while (Max>30 && Jude_has_mul_dev == 'y')
{
cout << "请重新输入最大值:" << endl;
cin >> Max;
}
cout << "请输入出题数量:";
cin >> subject_number;

int i = 0, j, k;
if ('y' == Jude_has_mul_dev)
{
random_number = rand() % 9 + 2;    //随机生成2~10个数
for (j = 0; j < subject_number; j++)    //设置题目数量
{
//清除数组元素
memset(Num, 0, sizeof(Num));
memset(op_arrays, 0, sizeof(op_arrays));
memset(fu, 0, sizeof(fu));

random_number = rand() % 9 + 2;    //随机生成2~10个数
for (i = 0; i < random_number; i++)
{
stringstream ss;
operation_character = rand() % (Max - min + 1) + min;
Num[i] = operation_character;
fuhao = rand() % 4 + 1;
switch (fuhao)
{
case 1:sign = "+"; break;
case 2:sign = "-"; break;
case 3:sign = "*"; break;
case 4:sign = "/"; break;
}
//若为除法则除数不为零
while (Num[i] == 0 && i >= 1)
{
if (op_arrays[i - 1] == "/")
{
operation_character = rand() % (Max - min + 1) + min;
Num[i] = operation_character;
}
}
op_arrays[i] = sign;

fu[4 * i] = w;
ss << Num[i];
ss >> fu[4 * i + 1];
fu[4 * i + 2] = w;
if (i != (random_number - 1))   //最后一次不产生符号
fu[4 * i + 3] = op_arrays[i];
else fu[4 * i + 3] = w;
}
Jude_has_brackets = rand() % 2 + 1;  //随机确定有无括号
switch (Jude_has_brackets)
{
case 1:
left = "(";
right = ")";
break;
case 2:
left = w;
right = w;
break;
}

for (i = 0; i < random_number; i++)
{
for (k = 0; k < (random_number - 1) / 2; k++)
{
fu[4 * k] = left;
if (left == "(")
{
fu[4 * k + 10] = right;
}
}
if ((fu[4 * i] == left) && (fu[4 * i + 2] == right))
{
fu[4 * i] = w;
fu[4 * i + 2] = w;
}

All[j] += fu[4 * i] + fu[4 * i + 1] + fu[4 * i + 2] + fu[4 * i + 3];
}
cout << j + 1 << "题. " << All[j] << "= " ;
for (int i = 0; i != All[j].size(); ++i)
{
//逐一加入每个字符,这里使用deque因为deque在两端删除添加的速度最快
coll0.push_back(All[j][i]);      //在尾部加入一个元素
}

//将coll0转换为后缀表达式coll1
for (int i = 0; i != All[j].size(); ++i)
{
char k = coll0.front();
coll0.pop_front();
if (k != ' ')        //消除空格
coll1.push_back(k);
}
//从coll中取出元素,分配元素到coll2和coll3中
allocate(coll1, coll2, coll3);

//计算后缀表达式
calculate(coll3, coll4);

double result = 0;
cin >> result;
if (result == coll4.top())
{
cout << "正确!" << endl;
true_num++;
cout << "计算结果为:" << coll4.top() << endl;
}
else
{
cout << "错误!" << endl;
false_num++;
cout << "计算结果为:" << coll4.top() << endl;
}
//将栈清空
coll4.pop();
}
if (true_num >= false_num)
cout << "恭喜你!您共做对" << true_num << "道题!" << "做错" << false_num << "道题!" << endl;
else
cout << "还需加油!您共做对" << true_num << "道题!" << "做错" << false_num << "道题!" << endl;
}
else
{
random_number = rand() % 9 + 2;    //随机生成2~10个数
for (j = 0; j < subject_number; j++)    //设置题目数量
{
//清除数组元素
memset(Num, 0, sizeof(Num));
memset(op_arrays, 0, sizeof(op_arrays));
memset(fu, 0, sizeof(fu));

random_number = rand() % 9 + 2;    //随机生成2~10个数
for (i = 0; i < random_number; i++)
{
stringstream ss;
operation_character = rand() % (Max - min + 1) + min;
Num[i] = operation_character;
fuhao = rand() % 2 + 1;
switch (fuhao)
{
case 1:sign = "+"; break;
case 2:sign = "-"; break;
}
op_arrays[i] = sign;

fu[4 * i] = w;
ss << Num[i];
ss >> fu[4 * i + 1];
fu[4 * i + 2] = w;
if (i != (random_number - 1))   //最后一次不产生符号
fu[4 * i + 3] = op_arrays[i];
else fu[4 * i + 3] = w;
}
Jude_has_brackets = rand() % 2 + 1;  //随机确定有无括号
switch (Jude_has_brackets)
{
case 1:
left = "(";
right = ")";
break;
case 2:
left = w;
right = w;
break;
}

for (i = 0; i < random_number; i++)
{
for (k = 0; k < (random_number - 1) / 2; k++)
{
fu[4 * k] = left;
if (left == "(")
{
fu[4 * k + 10] = right;
}
}
if ((fu[4 * i] == left) && (fu[4 * i + 2] == right))
{
fu[4 * i] = w;
fu[4 * i + 2] = w;
}

All[j] += fu[4 * i] + fu[4 * i + 1] + fu[4 * i + 2] + fu[4 * i + 3];
}
cout << j + 1 << "题. " << All[j] << "= " << endl;
for (int i = 0; i != All[j].size(); ++i)
{
//逐一加入每个字符,这里使用deque因为deque在两端删除添加的速度最快
coll0.push_back(All[j][i]);      //在尾部加入一个元素
}

//将coll0转换为后缀表达式coll1
for (int i = 0; i != All[j].size(); ++i)
{
char k = coll0.front();
coll0.pop_front();
if (k != ' ')        //消除空格
coll1.push_back(k);
}
//从coll中取出元素,分配元素到coll2和coll3中
allocate(coll1, coll2, coll3);

//计算后缀表达式
calculate(coll3, coll4);

double result = 0;
cin >> result;
if (result == coll4.top())
{
cout << "正确!" << endl;
true_num++;
cout << "计算结果为:" << coll4.top() << endl;
}
else
{
cout << "错误!" << endl;
false_num++;
cout << "计算结果为:" << coll4.top() << endl;
}
//将栈清空
coll4.pop();
}
if (true_num >= false_num)
cout << "恭喜你!您共做对" << true_num << "道题!" << "做错" << false_num << "道题!" << endl;
else
cout << "还需加油!您共做对" << true_num << "道题!" << "做错" << false_num << "道题!" << endl;
}
return 0;
}

//判断是否为括号
bool isPra(char c)
{
if (c == '(' || c == ')')
return true;
else
return false;
}

//获得符号的优先性
int getPri(char c)
{
switch (c)
{
case '+':
case '-':
return 0;    //如果是加减,返回0
break;
case '*':
case '/':
return 1;    //如果是乘除,返回1
break;
case '(':
case ')':
return -1;  //注意,这里将括号设为最低优先级,因此括号不会被弹出,除非遇到右括号
break;
}
return 2;
}

//判断符号的优先性
void check(char c, stack<char>& coll2, deque<char>& coll3)
{
if (coll2.empty())
{
coll2.push(c);
return;
}

if (isPra(c))
{
if (c == '(')
coll2.push(c);
else
{
//弹出所有元素直到遇到左括号
while (coll2.top() != '(')
{
char ch = coll2.top();
coll3.push_back(ch);
coll2.pop();
}

//当遇到左括号时,弹出但不加入coll3(后缀表达式中)--(“(”“)”都不放入后缀表达式中)
coll2.pop();  //弹出左括号
}
}
else    //如果不是括号
{
//取出栈顶元素,与当前符号进行优先性比较
char sym = coll2.top();

//比较两符号的优先性
if (getPri(c) <= getPri(sym))
{
//如果c的优先性比栈顶符号小或等于,弹出栈顶元素
coll2.pop();
//并将其压入coll3(后缀表达式)中
coll3.push_back(sym);
//递归调用check,比较当前符号c与下一个栈顶符号的优先性
check(c, coll2, coll3);
}
else
{
//如果c比栈顶符号优先级大,那将c压入coll2(操作符栈)中
coll2.push(c);
}
}
}

//从coll中取出元素,分配元素到coll2和coll3中
void allocate(deque<char>& coll1, stack<char>& coll2, deque<char>& coll3)
{
while (!coll1.empty())
{
char c = coll1.front();
coll1.pop_front();

if (c >= '0'&&c <= '9')
{
coll3.push_back(c);
//判断是否为两位数
if (!coll1.empty())
{
c = coll1.front();
if (c >= '0'&&c <= '9')
coll3.push_back('@');
}
}
else
{
//调用check函数,针对不同情况作出不同操作
check(c, coll2, coll3);
}

}

//如果输入结束,将coll2的元素全部弹出,加入后缀表达式中
while (!coll2.empty())
{
char c = coll2.top();
coll3.push_back(c);
coll2.pop();
}
}

//计算后缀表达式(修改)
void calculate(deque<char>& coll3, stack<double>& coll4)
{
while (!coll3.empty())
{
char c = coll3.front();   //取出第一个元素
double op = 0;
coll3.pop_front();   //并弹出此元素
//coll3.erase(coll3.begin());
//如果是操作数,压入栈中

//若是两位数在压入辅助数组后需要进行判断
if (c >= '0'&&c <= '9')
{
op = (c - '0');
coll4.push(op);
//cout<<"op="<<op<<endl;
}
else if (c == '@')            //如果是两位数则再读一位(若超过两位需要while扩展)
{
char d = coll3.front();
op = coll4.top();
coll4.pop();
op = op * 10 + (d - '0');
coll4.push(op);
coll3.pop_front();
}
else     //如果是操作符,从栈中弹出元素进行计算
{
double op1 = coll4.top();
coll4.pop();
double op2 = coll4.top();
coll4.pop();
switch (c)
{
case '+':
coll4.push(op2 + op1);
break;
case '-':
coll4.push(op2 - op1);
break;
case '*':
coll4.push(op2*op1);
break;
case '/':
coll4.push(op2 / op1);  //注意是op2(op)op1而不是op1(op)op2
break;
}
}
}
}


结果截图:







工作照:



总结反思:

本次只做了些辅助工作,本来经过上次的实验很有信心想通过完成这次实验来提高自己(确实有所提高,但没有达到预期),虽然花了足够多的时间,数组转换为字符串、添加真分数这些较为简单的步骤自己都没有完成,效率不高,自己总结下原因有二:1.结对编程对同组大牛有依赖心理 2.没有理清楚思路头绪上来就敲代码(总体表现很慌乱,不知所措),今后一定要先理清思路再动手,有一个明确的方向,要学的很多,努力程度还差很远,加油!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: