这是第三次要对四则运算设计程序实现,这次需要两个人一起编程实现,经过讨论,我们认为最好在两个人的前两次设计中挑选比较适合的一个进行修改。

      这次需要计算生成表达式的值并判断用户输入的值是否正确。

设计思路:

     关键是对结果的计算,可以通过数据结构中的栈实现,计算括号中的内容,首先从第一个字符开始压栈,遇到左括号开始记录位置,继续压栈直到遇到第一个右括号,计算中间式子的值。

程序代码:

 
  1 //赵承圣 2016.3.18
  2 #include<iostream>
  3 #include<ctime>
  4 #include<string>
  5 #include<sstream> 
  6 #include "SqStack.h"
  7 using namespace std;
  8 
  9 char ops[7] = { '+', '-', '*', '/', '(', ')', '=' };
 10 char cmp[7][7] = { { '>', '>', '<', '<', '<', '>', '>' },
 11                     { '>', '>', '<', '<', '<', '>', '>' },
 12                     { '>', '>', '>', '>', '<', '>', '>' },
 13                     { '>', '>', '>', '>', '<', '>', '>' },
 14                     { '<', '<', '<', '<', '<', '=', ' ' },
 15                     { '>', '>', '>', '>', ' ', '>', '>' },
 16                     { '<', '<', '<', '<', '<', ' ', '=' } };
 17 
 18 bool IsOperator(char ch)
 19 {
 20     for (int i = 0; i < 7; i++)
 21         if (ch == ops[i])
 22             return true;
 23     return false;
 24 }
 25 char Compare(char ch1, char ch2)
 26 {
 27     int i, m, n;
 28     char priority;
 29     for (i = 0; i < 7; i++) { //找到相比较的两个运算符在比较矩阵里的相对位置
 30         if (ch1 == ops[i])
 31             m = i;
 32         if (ch2 == ops[i])
 33             n = i;
 34     }
 35     priority = cmp[m][n];
 36     return priority;
 37 }
 38 
 39 bool Compute(double x, char op, double y, double &z)
 40 {
 41     switch (op) {
 42     case '+':    z = x + y;
 43         break;
 44     case '-':    z = x - y;
 45         break;
 46     case '*':    z = x * y;
 47         break;
 48     case '/':    if (fabs(y) > 1e-7) {
 49         z = x / y;
 50         break;
 51     }
 52                 else
 53                     cout << "除数为0,出错!" << endl;
 54         return false;
 55     }
 56     return true;
 57 }
 58 
 59 bool ExpEvaluation(char *str, double &result)
 60 {
 61     double a, b, v;
 62     char ch, op;
 63     int temp, i = 0;
 64     SqStack <char> optr(20);     //创建运算符栈optr
 65     SqStack <double> opnd(20);   //创建运算数栈opnd
 66     optr.Push('=');
 67     ch = str[i++];
 68     while (ch != '=' || optr.Top() != '=') {
 69         while (ch == ' ')   //跳过空格
 70             ch = str[i++];
 71         if (IsOperator(ch)) {  //是7种运算符之一
 72             switch (Compare(optr.Top(), ch)) {
 73             case '<':         //栈顶运算符优先级低
 74                 optr.Push(ch);
 75                 ch = str[i++];
 76                 break;
 77             case '=':         //脱括号并接收下一字符
 78                 optr.Pop();
 79                 ch = str[i++];
 80                 break;
 81             case '>':         //栈顶运算符优先级高,退栈并将运算结果入栈
 82                 op = optr.Top();
 83                 optr.Pop();
 84                 b = opnd.Top();
 85                 opnd.Pop();
 86                 a = opnd.Top();
 87                 opnd.Pop();
 88                 if (Compute(a, op, b, v)) { //计算v = a <op> b
 89                     opnd.Push(v);
 90                     break;
 91                 }
 92                 else {
 93                     result = 0;
 94                     return false;
 95                 }
 96             }
 97         }
 98         else {    //是数字
 99             temp = ch - '0';    //将字符转换为十进制数
100             ch = str[i++];
101             while (!IsOperator(ch) && ch != ' ') {
102                 temp = temp * 10 + ch - '0'; //将逐个读入运算数的各位转化为十进制数
103                 ch = str[i++];
104             }
105             opnd.Push(temp);    //数值入栈
106         }
107     }
108     result = opnd.Top();
109     return true;
110 }
111 
112 
113 
114 string IntToString(int & i)
115 {
116     string s;
117     stringstream ss(s);
118     ss << i;
119     return ss.str();
120 }
121 
122 
123 void checkcon0(int &num,string chnum)
124 {
125     while(num!=2&&num!=4)
126     {
127         if(chnum=="")
128         {
129             num=2;
130         }
131         else if(chnum=="")
132         {
133             num=4;
134         }
135         else
136         {
137             cout<<"输入不合法,请重新输入: ";
138             cin>>chnum;
139             cout<<endl;
140         }
141     }
142 }
143 void checkcon1(int &num1,string chnum)
144 {
145     while(num1!=1&&num1!=0)
146     {
147         if(chnum=="")
148         {
149             num1=1;
150         }
151         else if(chnum=="")
152         {
153             num1=0;
154         }
155         else
156         {
157             cout<<"输入不合法,请重新输入: ";
158             cin>>chnum;
159             cout<<endl;
160         }
161     }
162 
163 }
164 void check(int &num2,string chnum)
165 {
166     num2 = std::atoi(chnum.c_str() );
167     while(num2<=0)
168     {
169         cout<<"输入不合法,请重新输入: ";
170         cin>>chnum;
171         cout<<endl;
172         num2 = std::atoi(chnum.c_str() );
173     }
174 }
175 
176 int main()
177 {
178     //数据定义部分
179     srand((int)time(NULL));
180     int control[2],itemnum, num_max, num_min, num_num, bracket_num;
181     string chnum[5];
182     string express = "";
183     char symbol[4],c[20];;                    //随机计算符号数组
184     symbol[0] = '+';
185     symbol[1] = '-';
186     symbol[2] = '*';
187     symbol[3] = '/';
188 
189     //输入及判断部分
190     cout << "是否有乘除(是/否):  ";
191     cin >> chnum[0];
192     checkcon0(control[0],chnum[0]);
193     cout << "是否有括号(是/否):  ";
194     cin >> chnum[1];
195     checkcon1(control[1],chnum[1]);
196     cout << "数字最大取值:  ";
197     cin >> chnum[2];
198     check(num_max,chnum[2]);
199     cout << "数字最小取值:  ";
200     cin >> chnum[3];
201     check(num_min,chnum[3]);
202     cout<<"式子数量: ";
203     cin>>chnum[4];
204     check(itemnum,chnum[4]);
205 
206     string *item=new string[itemnum];
207     double *result = new double[itemnum];
208     double *uans = new double[itemnum];
209     int rightnum = 0;
210 
211     //算式生成部分
212     for (int count = 0; count<itemnum; count++)
213     {
214         num_num = rand() % 10;
215         string *str = new string[num_num];
216         if (num_num == 0 || num_num == 1)
217         {
218             count--;
219             continue;
220         }
221 
222         //定义并初始化动态数组 num:数字数组  symnum:符号选择数组  sym:符号数组
223         int *num = new int[num_num];
224         int *symnum = new int[num_num - 1];
225         char *sym = new char[num_num - 1];
226 
227         int bracket_leftposition, bracket_rightposition;
228         int *bracket_left_time = new int[num_num];           //定义左、右括号生成次数数组,下标为数字位置
229         int *bracket_right_time = new int[num_num];
230         string *bracket_left = new string[num_num]();        //定义左右括号字符串型数组
231         string *bracket_right = new string[num_num]();
232         for (int rcount = 0; rcount<num_num; rcount++)          //左、右括号生成次数初始化
233         {
234             bracket_left_time[rcount] = 0;
235             bracket_right_time[rcount] = 0;
236         }
237 
238         //给参与计算的数赋值(指定数值范围)
239         for (int cnum = 0; cnum<num_num; cnum++)
240         {
241             num[cnum] = rand() % (num_max - num_min + 1) + num_min;
242         }
243 
244         //随机生成式子的各个位置的符号
245         for (int snum = 0; snum<num_num - 1; snum++)
246         {
247             symnum[snum] = rand() % control[0];
248             sym[snum] = symbol[symnum[snum]];
249         }
250 
251 
252         if (control[1] == 0)
253         {
254             bracket_num = rand() % 7 + 1;
255             //生成括号次数
256             for (int bcount = 0; bcount<bracket_num; bcount++)
257             {
258                 bracket_leftposition = rand() % num_num;                //随机生成左右括号的位置
259                 bracket_rightposition = rand() % num_num;
260                 if ((bracket_leftposition >= bracket_rightposition)||((bracket_leftposition==0)&&(bracket_rightposition==num_num-1)))     //先剔除部分一次性在一个数左右同时生成左右括号和在整个式子前后生成式子的情况
261                 {
262                     continue;
263                 }
264                 bracket_left_time[bracket_leftposition]++;            //该位置数左括号生成次数+1
265                 bracket_right_time[bracket_rightposition]++;
266             }
267         }
268         for (int stnum = 0; stnum < num_num-2; stnum++)
269         {
270             if ((symbol[symnum[stnum]] == '/') && (symbol[symnum[stnum + 1]] == '/'))
271             {
272                 bracket_left_time[stnum]++;
273                 bracket_right_time[stnum + 1]++;
274             }
275         }
276         for (int snum = 0; snum < num_num ; snum++)
277         {
278             
279             if (bracket_left_time[snum] == 1)
280             {
281                 bracket_left[snum] = "(";
282             }
283             if (bracket_left_time[snum] == 2)
284             {
285                 bracket_left[snum] = "((";
286             }
287             if (bracket_left_time[snum] == 3)
288             {
289                 bracket_left[snum] = "(((";
290             }
291             if (bracket_right_time[snum] == 1)
292             {
293                 bracket_right[snum] = ")";
294             }
295             if (bracket_right_time[snum] == 2)
296             {
297                 bracket_right[snum] = "))";
298             }
299             if (bracket_right_time[snum] == 3)
300             {
301                 bracket_right[snum] = ")))";
302             }
303             for (int bpcount = 0; bpcount<num_num; bpcount++)            //再次扫描数字左右括号生成次数相等的情况并排除
304             {
305                 if (bracket_left_time[bpcount] == bracket_right_time[bpcount])
306                 {
307                     bracket_right[bpcount] = "";
308                     bracket_left[bpcount] = "";
309                 }
310             }
311         }
312 
313         //输出算式
314         for (int ph = 0; ph<num_num - 1; ph++)
315         {
316             cout << bracket_left[ph] << num[ph] << bracket_right[ph] << sym[ph];
317         }
318         cout << bracket_left[num_num - 1] << num[num_num - 1] << bracket_right[num_num - 1] << "= ";
319 
320         
321         for (int i = 0; i < num_num; i++)
322         {
323             int &temp = num[i];
324             str[i] = IntToString(temp);
325         }
326         for (int ph = 0; ph<num_num - 1; ph++)
327         {
328             express =express+bracket_left[ph]+str[ph]+bracket_right[ph]+sym[ph];
329         }
330         express = express + bracket_left[num_num - 1] +str[num_num - 1]+ bracket_right[num_num - 1];
331         item[count] = express+"=";
332         
333         strcpy(c, item[count].c_str());
334         ExpEvaluation(c, result[count]); //求表达式的值
335         
336         cin >> uans[count];
337         if (uans[count] == result[count])
338         {
339             rightnum++;
340             cout << "回答正确" << endl;
341         }
342         else
343         {
344             cout << "回答错误" << endl;
345             cout << "正确答案是  " << result[count] << endl;
346         }
347         
348 
349         express="";
350 
351         if (count == 29)
352         {
353             delete[]num;
354             delete[]symnum;
355             delete[]sym;
356             delete[]bracket_left_time;
357             delete[]bracket_right_time;
358             delete[]bracket_left;
359             delete[]bracket_right;
360             delete[]item;
361             delete[]str;
362             delete[]result;
363         }
364 
365     }
366     cout << "本次测试共答对 "<< rightnum <<" 道题"<< endl;
367 
368     system("pause");
369     return 0;
370 }

SqStack.h 

#ifndef _SQSTACK_H_
#define _SQSTACK_H_
//定义顺序栈类
template <class ElemType>//声明一个类模板
class SqStack
{
public://顺序栈类的各成员函数
    SqStack(int m = 100);
    ~SqStack();
    void Clear();
    bool Empty() const;
    int Length() const;
    ElemType & Top() const;
    void Push(const ElemType &e);
    void Pop();
private://顺序栈类的数据成员
    ElemType *m_base;//基地址指针
    int m_top;//栈顶指针
    int m_size; //向量空间大小
};
//构造函数,分配m个结点的顺序空间,构造一个空的顺序栈。
template <class ElemType>
SqStack <ElemType>::SqStack(int m)
{
    m_top = 0;
    m_base = new ElemType[m];
    m_size = m;
}//SqStack
 //析构函数,将栈结构销毁。
template <class ElemType>
SqStack <ElemType>::~SqStack()
{
    if (m_base != NULL) delete[] m_base;
}//~SqStack
 //清空栈。
template <class ElemType>
void SqStack <ElemType>::Clear()
{
    m_top = 0;
}//Clear
 //判栈是否为空,若为空,则返回true,否则返回false。
template <class ElemType>
bool SqStack <ElemType>::Empty() const
{
    return m_top == 0;
}//Empty
 //求栈的长度。
template <class ElemType>
int SqStack <ElemType>::Length() const
{
    return m_top;
}//Length
 //取栈顶元素的值。先决条件是栈不空。
template <class ElemType>
ElemType & SqStack <ElemType>::Top() const
{
    return m_base[m_top - 1];
}//Top
 //入栈,若栈满,则先扩展空间。插入e到栈顶。
template <class ElemType>
void SqStack <ElemType>::Push(const ElemType &e)
{
    if (m_top >= m_size) {            //若栈满,则扩展空间。 
        ElemType *newbase;
        newbase = new ElemType[m_size + 10];
        for (int j = 0; j < m_top; j++)
            newbase[j] = m_base[j];
        delete[] m_base;
        m_base = newbase;
        m_size += 10;
    }
    m_base[m_top++] = e;
}//Push
 //出栈,弹出栈顶元素。先决条件是栈非空。
template <class ElemType>
void SqStack <ElemType>::Pop()
{
    m_top--;
}//Pop
#endif
#pragma once

 


这次程序还有未完成的地方,对于连续除法未明确优先级,我们将继续努力完成这次程序。

团队成员:赵承圣、罗元浩   http://www.cnblogs.com/lyhao

 

 posted on 2016-03-19 20:31  呼噜~呼噜  阅读(238)  评论(1编辑  收藏  举报