zoukankan      html  css  js  c++  java
  • 数式计算(递归解法)_四则运算

      1 /**
      2 *注:1.有一个bug(以及未知什么bug) 我已知的是: (a@b)(ps:@为运算符),这种带括号的表达式不能单独的出现,否则异常退出,,但是只要(a@b)@n
      3 
      4 带括号的表达式出现任意+,-,*,/的运算都能进行正常运算(前面 n@(a@b)也不可以)。。。不知道为什么()表达式后面没有操作时会异常退出。
      5 *不知道如何解决。希望感兴趣的人帮帮忙!
      6 
      7 //--------------------------------------------
      8 *一般的数式计算(允许括号的)需要通过栈来实现,但是其实对一些新手(我还没学数据结构)来说,用递归其实也是能很好的实现的。而且也很易于理解。
      9 *主要思路是-判断是有括号,无括号情况,有乘除和无乘除。有乘除时将乘除先算,算出来的值取代乘除的算式。
     10 *将括号中的数先算,将算出来的式子的值(括号中也会进行判断是否有无括号,有无乘除)将算出来的数取代原来的算式,然后递归.
     11 *最后的结束条件(判断其中运算符的数量): 只要算一个单一运算符的式子,因为在递归中所有的复杂的式子都被替换成了值。
     12 */
     13 
     14 #include<iostream>
     15 #include<cctype>
     16 #include<vector>
     17 #include<cstdlib>
     18 #include<cstring>
     19 #include<string>
     20 
     21 #define Jia 100001
     22 #define Jian 100002
     23 #define Chen 100003
     24 #define Chu 100004
     25 #define Qian 100005
     26 #define Hou 100006
     27 
     28 using namespace std;
     29 
     30 void Exchange(vector<double>& v, string s);   //将字符串转换成double型数
     31 double Calculate_Single(vector<double> v);    //进行数式计算
     32 double Count(double a, double b, double c);   //计算一组算式
     33 double integer(char c,double &rin);           // 将连续数字字符串转换为整数
     34 
     35 double integer(char c,double &rin)       // 将连续数字字符串转换为整数
     36 {
     37     rin = rin*10 + (c-'0');
     38     return rin;
     39 }
     40 
     41 void Exchange(vector<double>& v, string s)
     42 {
     43     char *p = &s[0];
     44     double re;
     45     while (*p) {
     46         re = 0;
     47         for ( ; *p; ++p) {
     48             if (isdigit(*p))           //如果是数字字符
     49                 integer(*p, re);       //转换成整数
     50             else{
     51                 if (*p == '(') { v.push_back(Qian); p++;}
     52                 break;
     53             }
     54         }
     55         if (re)
     56             v.push_back(re);
     57         if (*p == '')
     58             break;
     59         p--;
     60         while (*p++) {
     61             if (*p == '+') { v.push_back(Jia); continue;    }
     62             if (*p == '-') { v.push_back(Jian); continue;   }
     63             if (*p == '*') { v.push_back(Chen); continue;   }
     64             if (*p == '/') { v.push_back(Chu); continue;    }
     65             if (*p == '(') { v.push_back(Qian); continue;    }
     66             if (*p == ')') { v.push_back(Hou); continue;    }
     67             if (isdigit(*p))
     68                 break;
     69         }
     70     }
     71     //    cout << re << endl;        //debug
     72 }
     73 
     74 double Count(double a, double b, double c) {
     75     if (c == Jia)  return a + b;
     76     if (c == Jian) return a - b;
     77     if (c == Chen) return a * b;
     78     if (c == Chu)  return a / b;
     79     cerr << "运算出错,运算符不为+、-、*、/ !
    ";
     80     exit(1);
     81 }
     82 
     83 //思路:递归--将乘除,括号这些地方的算式算成值,替换到只有加减的式子中去,最后这个只要算一个只有加减的式子即可
     84 double Calculate_Single(vector<double> v)  //进行数式计算带括号--用递归实现
     85 {
     86     unsigned jia = 0, jian = 0, cheng = 0, chu = 0, qian = 0, hou = 0;
     87     for (auto it = v.begin(); it != v.end(); ++it) {    //遍历v中每个元素,数一共有多少个操作符
     88         if (*it == Jia)    jia++;
     89         else if (*it == Jian) jian++;
     90         else if (*it == Chen) cheng++;
     91         else if (*it == Chu) chu++;
     92         else if (*it == Qian) qian++;
     93         else if (*it == Hou) hou++;
     94     }
     95     //    for (auto t : v)   //debug
     96     //        cout  << t << "	" << endl;
     97 
     98     if (jia + jian + cheng + chu == 1) {       //最后一步--只算一个算式
     99         if (jia == 1) return v[0] + v[2];
    100         if (jian == 1) return v[0] - v[2];
    101         if (cheng == 1) return v[0] * v[2];
    102         if (chu == 1) return v[0] / v[2];
    103     }
    104    if (qian + hou == 0) {                                                //无括号的情形
    105         if (cheng + chu == 0 ) {                                         //无乘除情形
    106             vector<double> vv;                                            //对一组数进行操作
    107             double re = Count(v[0], v[2], v[1]); //只对一对算式进行操作
    108             vv.push_back(re);                                              //将一对算式的结果推入底部,相当于用答案取代了那个算式
    109             for (auto i = v.begin() + 3; i != v.end(); ++i) {   //将上一个算式后的所有字符添加vv到底部
    110                 vv.push_back(*i);
    111             }
    112             return Calculate_Single(vv);   //用递归实现--相当于将一处的算式替换成了数字
    113         }
    114         else {       //有乘除--目标:将指针一直前进到乘/除字符的位置t,计算该算式,保存乘/除前面所有的字符,再保存乘除算成的值,再保存乘除后的算式
    115             int t;    //标志位置-乘或除的位置
    116             vector<double> vv;  //用来保存计算过乘除的式子
    117             for (t = 0; v[t] != Chen && v[t] != Chu; ++t);  //推进到乘除的地方
    118             double re = Count(v[t-1], v[t+1], v[t]);           //计算乘除式子
    119             for (int i = 0; i < t-1; i++) {                           //将乘除前面的式子push_back
    120                 vv.push_back(v[i]);            
    121             }
    122             vv.push_back(re);                                                     //再替换乘除的式子为数值
    123             for (auto it = v.begin() + t + 2; it != v.end(); ++it) {  //将乘除后面式子保存到vv中
    124                 vv.push_back(*it);
    125             }
    126             return Calculate_Single(vv);                                       //递归--一直递归到式子中只有一个式子的情况
    127         }
    128     }
    129     else {        //有括号的情况
    130         vector<double> vv, vvv;             //vv--是保存将括号中计算结束后的式子,vvv--保存括号中的式子并计算出
    131         int q, h;                                     //q -- 前括号的位置,h--后括号的位置
    132         double re;                    
    133         for (h = 0; v[h] != Hou; ++h);    //推进到后括号的位置
    134         for (q = h; v[q] != Qian; --q);     //后退到前括号的位置
    135         for (int i = q + 1; i < h; ++i)       //将括号中的式子push到vvv底部
    136             vvv.push_back(v[i]);
    137         re = Calculate_Single(vvv);       //将括号中的式子递归求出
    138         for (int i = 0; i < q; i++) {        //将前括号中的式子push_back
    139             vv.push_back(v[i]);        
    140         }
    141         vv.push_back(re);                                                   //将括号中的式子计算出push到vv底部
    142         for (auto it = v.begin() + h + 1; it != v.end(); ++it)  //将括号后的式子push_back
    143             vv.push_back(*it);
    144         return Calculate_Single(vv);                                    //再次递归进行计算--一直到只有一个式子的时候终止
    145     }
    146     cerr << "Bug:Calculate_Single 失效!" << endl;
    147     return 0;
    148 }
    149 
    150 int main()
    151 {
    152     vector<double> data;
    153     string line;
    154     cin >> line;
    155     Exchange(data, line);
    156     double result = Calculate_Single(data);
    157     cout << result << endl;
    158     return 0;
    159 }

     

  • 相关阅读:
    BZOJ 2034 【2009国家集训队】 最大收益
    vijos P1780 【NOIP2012】 开车旅行
    BZOJ 2115 【WC2011】 Xor
    BZOJ 3631 【JLOI2014】 松鼠的新家
    BZOJ 4717 改装
    BZOJ 2957 楼房重建
    BZOJ 4034 【HAOI2015】 T2
    BZOJ 1834 【ZJOI2010】 network 网络扩容
    BZOJ 2440 【中山市选2011】 完全平方数
    BZOJ 2733 【HNOI2012】 永无乡
  • 原文地址:https://www.cnblogs.com/douzujun/p/5475947.html
Copyright © 2011-2022 走看看