由于自身思维不够活跃,思考问题逻辑不够清晰,所以小弟的师傅给小弟我布置了个作业,字符串表达式求值,以此希望达到锻炼我思维逻辑能力的目的。
历时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 }`
View Code

相关文章: