由于自身思维不够活跃,思考问题逻辑不够清晰,所以小弟的师傅给小弟我布置了个作业,字符串表达式求值,以此希望达到锻炼我思维逻辑能力的目的。
历时14天,完成作业,相关知识以及技术并不高深,目的在于锻炼逻辑思维能力。在此也想跟有相关需要的同学们分享下解题思路,有不足之处也希望大家不吝赐教,指点出来。谢谢。
解决该问题时首先要解决判断运算符优先级问题,后来了解到后缀表达式(即逆波兰表达式)后,决定先将表达式分解成逆波兰表达式 ,然后再根据每个运算符取出数字进行相应的运算。计算到最后即为表达式的值
涉及string字符串、动态数组vector、逆波兰表达式(网上由相应的解析,书上并没有出现),迭代器(主要起取出以及作转换范围使用)的相关知识。
低配版(仅支持0-9的正整数计算,可以计算的运算符包含+ - * / % ^ & |)
代码如下:
1 //原型: double Exper(const char * expr); 2 //使用: double retval = Expr("1*2+(10/4)-3^1234"); 3 #include<iostream> 4 #include<string> 5 #include<sstream> 6 #include<vector> 7 #include<stack> 8 #include<cstdio> 9 using namespace std; 10 11 bool gettruefalse(char a) //判断当前符号是否为符号 12 { 13 if (a == '+' || a == '-' || a == '*' || a == '/' || a == '%' || \ 14 a == '^' || a == '|' || a == '&' || a == '(' || a == ')') 15 return true; 16 else 17 return false; 18 } 19 20 int getpriority(char c) //判断当前运算符的优先级 21 { 22 int temp; 23 if (c == '(') 24 temp = 6; 25 else if (c == '*' || c == '/' || c == '%') 26 temp = 5; 27 else if (c == '+' || c == '-') 28 temp = 4; 29 else if (c == '&') 30 temp = 3; 31 else if (c == '^') 32 temp = 1; 33 else if (c == '|') 34 temp = 1; 35 else if (c == ')') //如果为')',则一直将符号取出放入新字符串,直到遇到'('(6) 36 temp = 0; 37 return temp; 38 } 39 40 string getnbl(string str) //将原字符串转为逆波兰形式的字符串 41 { 42 string ok;//用于存放转换成后缀表达式的容器 43 vector<char>flag;//用于存放转换时的符号容器 44 45 while (str.length() != 0)//将旧字符串转换完成前,无限循环 46 { 47 for (int a = 0; a < str.length(); a++) //遍历字符串 48 { 49 if (gettruefalse(str[a])) //如果当前字符为符号 50 { 51 //如果符号容器为空,或者当前符号优先级大于符号容器优先级,或者符号容器最后一个符号为(,压入 52 if (flag.size() == 0 || (getpriority(str[a]) > getpriority(*(flag.end() - 1))) || getpriority(*(flag.end() - 1)) == 6) 53 { 54 flag.push_back(str[a]);//将当前符号放入符号容器 55 str.erase(str.begin(), str.begin() + 1); //截断旧字符串中的符号 56 break;//跳出for循环,重新遍历 57 } 58 else if (getpriority(str[a]) == 0) //是)吗 59 { 60 str.erase(str.begin(), str.begin() + 1);//删掉旧字符串的),并将符号容器的符号移到新字符串,直到遇到( 61 while (getpriority(*(flag.end() - 1)) != 6)//遇到(之前 无限弹出容器里的符号 62 { 63 ok += *(flag.end() - 1);//将符号容器的符号添加到新字符 64 flag.erase(flag.end() - 1);//将刚被添加到新字符的字符删去 65 } 66 if ((getpriority(*(flag.end() - 1)) == 6))//将(去掉 67 { 68 flag.erase(flag.end() - 1); 69 break;//跳到开头while循环处 70 } 71 } 72 else if (getpriority(str[a]) <= getpriority(*(flag.end() - 1))) //当前符号优先级小于或等于符号容器最后一个符号 73 { 74 ok += *(flag.end() - 1);//将符号容器的符号添加到新字符 75 flag.erase(flag.end() - 1);//将刚被添加到新字符的字符删去 76 break; 77 } 78 } 79 else //如果当前字符不为符号(即为数字或小数点) 80 { 81 ok += str[a];//将该数字转入新的字符串 82 str.erase(a, 1); //在旧字符串中删除该数字 83 break;//跳出for循环,重新开始遍历 84 } 85 } 86 } 87 //旧字符串清空后,将临时存放点的字符串依次取出放入新字符中 88 while (flag.size() != 0) 89 { 90 ok += *(flag.end() - 1); 91 flag.erase(flag.end() - 1); 92 } 93 return ok; 94 } 95 96 int jisuan(int a, char b, int c) //根据符号取数字进行相应的计算 97 { 98 int num = 0;//计算结果 99 if (b == '+') 100 num = a + c; 101 else if (b == '-') 102 num = a - c; 103 else if (b == '*') 104 num = a * c; 105 else if (b == '/') 106 num = a / c; 107 else if (b == '%') 108 num = a % c; 109 else if (b == '^') 110 num = a ^ c; 111 else if (b == '&') 112 num = a & c; 113 else if (b == '|') 114 num = a | c; 115 else if (b == 'M') 116 num = a && c; 117 else if (b == 'N') 118 num = a || c; 119 return num; 120 } 121 122 int getcount(string nbl) //将逆波兰形式的字符串进行转换为数字类型然后进行符号的运算 123 { 124 vector<int>nums; 125 int a = 0; 126 int answer; //存放结果 127 string zhuanhuan; 128 while (a < nbl.size()) 129 { 130 if (gettruefalse(nbl[a]))//如果为符号 131 { //从数字容器中去除倒数第二的数作为A,最后一个数作为B,执行该符号的运算 132 answer = jisuan(*(nums.end() - 2), nbl[a], *(nums.end() - 1)); 133 nums.erase(nums.end() - 2, nums.end()); 134 nums.push_back(answer); 135 a++;//遍历下一个字符 136 } 137 else //数字时 压入数字容器 138 { 139 zhuanhuan += nbl[a]; 140 answer = atof(zhuanhuan.c_str()); 141 nums.push_back(answer); 142 zhuanhuan.clear(); 143 a++; 144 } 145 } 146 return *(nums.end() - 1); //容器最后一位数即为结果 147 } 148 149 int main() 150 { 151 char ch[100]; 152 cout << "输入你要计算的字符串表达式(仅支持0-9的正整数运算):" << endl; 153 gets_s(ch); 154 cout << "字符串的原内容为:" << ch << endl; 155 156 string str(ch);//用于进行转换操作的字符串 157 string nbl;//用于存放转换成后缀表达式的容器 158 nbl = getnbl(str);//调用函数 将字符串转为逆波兰字符串 159 cout << "转为逆波兰表达式后:" << nbl << endl; 160 int num = getcount(nbl); 161 cout << "字符串:" << ch << "的结果为:" << num << endl; 162 163 system("pause"); 164 fflush(stdin); 165 return 0; 166 }`