• 关于实现字符串表达式求值


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

    完全版(此时可以计算正负的整数(不支持小数点),运算符也包含+ - * / % & && ^ | ||):

      1 //原型: double Exper(const char * expr);
      2 //使用: double retval = Expr("1*2+(10/4)-3^1234");
      3 #include<iostream>
      4 #include<string>
      5 #include<vector>
      6 #include<cstdio>
      7 using namespace std;
      8 
      9 int gettruefalse(char a) //判断当前符号是否为运算符或数字
     10 {
     11 if (a == '1' || a == '2' || a == '3' || a == '4' || a == '5' || \
     12 a == '6' || a == '7' || a == '8' || a == '9' || a == '0')
     13 return 2;
     14 else if (a == '+' || a == '-' || a == '*' || a == '/' || a == '%' || \
     15 a == '^' || a == '|' || a == '&' || a == '(' || a == ')' || a == 'M' || a == 'N')
     16 return 1;
     17 else
     18 return 0;
     19 }
     20 
     21 int getpriority(char c) //优先级排列
     22 {
     23 int temp;
     24 if (c == '(')
     25 temp = 8;
     26 else if (c == '*' || c == '/' || c == '%')
     27 temp = 7;
     28 else if (c == '+' || c == '-')
     29 temp = 6;
     30 else if (c == '&')
     31 temp = 5;
     32 else if (c == '^')
     33 temp = 4;
     34 else if (c == '|')
     35 temp = 3;
     36 else if (c == 'M') //等同于&&
     37 temp = 2;
     38 else if (c == 'N') //等同于||
     39 temp = 1;
     40 else if (c == ')') //如果为')',则一直将符号取出放入新字符串,直到遇到'('(6)
     41 temp = 0;
     42 return temp;
     43 }
     44 
     45 void getvariant(string &str)
     46 {
     47 int a = 0;//用于遍历
     48 for (a = 0; a < str.size(); a++) //将原字符串中的-(符号)用相应的标识符替换
     49 {
     50 if ((a == 0) && (str[a] == '-'))
     51 {
     52 str[a] = '.';
     53 }
     54 else if ((str[a] == '-') && (gettruefalse(str[a - 1]) == 1) && (str[a - 1] != ')')) //找到-并确认当前是否为符号
     55 {
     56 str[a] = '.';
     57 }
     58 }
     59 for (a = 0; a < str.size(); a++) //将原字符串中的||、&&用相应的标识符替代
     60 {
     61 if (str[a] == '|' && str[a + 1] == '|')
     62 {
     63 str[a + 1] = 'N';
     64 str.erase(a, 1);
     65 }
     66 if (str[a] == '&' && str[a + 1] == '&')
     67 {
     68 str[a + 1] = 'M';
     69 str.erase(a, 1);
     70 }
     71 }
     72 }
     73 
     74 string getnbl(string str)
     75 {
     76 getvariant(str);//调用函数用标记符替换字符串中的||、&&、-(负号)
     77 string ok;//用于存放转换成后缀表达式的容器
     78 vector<char>flag;//用于存放转换时的符号容器
     79 int a = 0;//用于作为遍历字符串的下标
     80 int b = a;//!b作为开始遍历数字的起始点
     81 
     82 while (a <str.length())//遍历整个字符串
     83 {
     84 if ((gettruefalse(str[a])) == 1)//当前字符为符号
     85 {
     86 //符号容器为空或者当前符号优先级大于容器末尾符号优先级,或当前容器末尾为(,压入容器
     87 if (flag.size() == 0 || (getpriority(str[a]) > getpriority(*(flag.end() - 1))) \
     88 || *(flag.end() - 1) == '(')
     89 {
     90 flag.push_back(str[a]);
     91 a++;
     92 }
     93 else if (str[a] == ')') //如果为) 不压入,弹出容器符号 直到遇到(
     94 {
     95 while (*(flag.end() - 1) != '(')//当前符号不为(,则一直弹出容器符号
     96 {
     97 ok += *(flag.end() - 1);
     98 ok += ' '; //每个符号以空格作为间隔
     99 flag.erase(flag.end() - 1);
    100 }
    101 flag.erase(flag.end() - 1);//删掉容器中的(
    102 a++;//跳过')'符号
    103 }
    104 else if (getpriority(str[a]) <= getpriority(*(flag.end() - 1)))//当前符号优先级小于或等于符号容器最后一个符号
    105 {
    106 ok += *(flag.end() - 1);//将符号容器的符号添加到新字符
    107 ok += ' ';
    108 flag.erase(flag.end() - 1);//将刚被添加到新字符的字符删去
    109 }    
    110 }
    111 else //不为符号,则遍历字符串找到符号
    112 {
    113 b = a; //记录当前开始遍历的位置
    114 while(a<str.size())
    115 {
    116 if ( (gettruefalse(str[a]) == 1)) //当当前字符为符号
    117 {
    118 ok.append(str.begin() + b, str.begin() + a);//将遍历的起始位置到发现符号的位置的所有字符拼接到新的字符串,并加上空格作为间隔
    119 ok += ' ';
    120 break; //跳出for循环 重新进行判断
    121 }
    122 else if ((a==(str.size()-1)) && (gettruefalse(str[a]) == 2)) //已经遍历到最后一个字符了 且最后一个字符为数字
    123 {
    124 a++;
    125 ok.append(str.begin() + b, str.begin() + a);//将遍历的起始位置到发现符号的位置的所有字符拼接到新的字符串,并加上空格作为间隔
    126 ok += ' ';
    127 break; //跳出for循环 重新进行判断
    128 }
    129 a++;
    130 }
    131 }
    132 }
    133 while (flag.size() != 0) //遍历完原字符串后,将符号容器的符号全部弹出
    134 {
    135 ok += *(flag.end() - 1);
    136 ok += ' '; //每个符号以空格作为间隔
    137 flag.erase(flag.end() - 1);
    138 }
    139 return ok;
    140 }
    141 
    142 int getanswer(int a, char b, int c)
    143 {
    144 int num = 0;//计算结果
    145 if (b == '+') 
    146 num = a + c;
    147 else if (b == '-')
    148 num = a - c;
    149 else if (b == '*')
    150 num = a * c;
    151 else if (b == '/')
    152 num = a / c;
    153 else if (b == '%')
    154 num = a % c;
    155 else if (b == '^')
    156 num = a ^ c;
    157 else if (b == '&')
    158 num = a & c;
    159 else if (b == '|')
    160 num = a | c;
    161 else if (b == 'M')
    162 num = a && c;
    163 else if (b == 'N')
    164 num = a || c;
    165 return num;
    166 
    167 }
    168 
    169 int getcount(string nbl) //计算逆波兰表达式的
    170 {
    171 int num=0;//结果
    172 string zhuanhuan;
    173 vector<int> nums;//数字容器
    174 int a = 0;//遍历字符串下标
    175 int b = a;//记录开始遍历时的下标
    176 while (a < nbl.size())
    177 {
    178 if (gettruefalse(nbl[a])==1) //当前为符号
    179 {
    180 if (((nbl[a] == '/') || (nbl[a] == '%')) && (*(nums.end() - 1) == 0)) //计算除法和求余时,如果被除数为0,报错
    181 {
    182 cout << "除数不能为0,程序退出" << endl;
    183 system("pause");
    184 exit(-1);
    185 }
    186 
    187 num = getanswer(*(nums.end() - 2), nbl[a], *(nums.end() - 1));//弹出数字容器的2个数字 并根据符号去计算这2个数字
    188 nums.erase(nums.end() - 2, nums.end());//计算后去掉这2个数字,并将结果重新放入容器中
    189 nums.push_back(num);
    190 a++;//遍历下一个字符
    191 }
    192 else if (nbl[a] == ' ')
    193 {
    194 a++;
    195 }
    196 else
    197 {
    198 b = a;//记录开始找空格的位置
    199 while (a<nbl.size())
    200 {
    201 if (nbl[a] == ' ')//找到空格
    202 {
    203 if (nbl[b] == '.') //如果该数为负数(起始处为.)
    204 {
    205 nbl[b] = '-'; //将小数点转换为负号
    206 }
    207 zhuanhuan.append(nbl.begin() + b, nbl.begin() + a);
    208 num = atof(zhuanhuan.c_str()); //将该字符串转换为数字 并压入数字容器中
    209 zhuanhuan.clear();
    210 nums.push_back(num);
    211 break;
    212 }
    213 a++;
    214 }
    215 
    216 }
    217 }
    218 num = *(nums.end() - 1);
    219 return num;
    220 }
    221 
    222 int main()
    223 {
    224 char ch[100];
    225 cout << "输入你要计算的字符串表达式(仅支持整数运算):" << endl;
    226 gets_s(ch);
    227 string str(ch);//用于进行转换操作的字符串
    228 int s = 0;
    229 while (s < str.size())//检查用户输入表达式是否正确
    230 {
    231 if (gettruefalse(str[s]) == 0)
    232 {
    233 cout << "字符串表达式输入错误" << endl;
    234 system("pause");
    235 return 0;
    236 }
    237 s++;
    238 }
    239 string nbl;//用于存放转换成后缀表达式的容器
    240 nbl = getnbl(str);//调用函数 将字符串转为逆波兰字符串
    241 int num;//表达式结果
    242 num = getcount(nbl);    
    243 cout << "转为逆波兰表达式后:" << nbl << ",.(-)、M(&&)、N(|| )为标记符"<<endl;
    244 cout << "字符串表达式:" << ch << "的结果为:" << num << endl;
    245 cout << "结果为:" << num << endl;
    246 system("pause");
    247 fflush(stdin);
    248 return 0;
    249 }
    View Code

    运行结果:

  • 相关阅读:
    jQuary学习の三の效果展示
    jQuary学习の二の语法
    jQuary学习の一の初期准备
    js备战春招の四のjs函数
    javascript JSON
    js备战春招の四の表单
    js备战春招の四の严格模式
    290. Word Pattern--Easy
    546. Remove Boxes--Hard
    牛客网-华为-2020届校园招聘上机考试-3
  • 原文地址:https://www.cnblogs.com/aaaguai/p/11129853.html
Copyright © 2020-2023  润新知