这是第三次要对四则运算设计程序实现,这次需要两个人一起编程实现,经过讨论,我们认为最好在两个人的前两次设计中挑选比较适合的一个进行修改。
这次需要计算生成表达式的值并判断用户输入的值是否正确。
设计思路:
关键是对结果的计算,可以通过数据结构中的栈实现,计算括号中的内容,首先从第一个字符开始压栈,遇到左括号开始记录位置,继续压栈直到遇到第一个右括号,计算中间式子的值。
程序代码:
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