123
返回列表 发新帖
楼主: wwwyhx
跳转到指定楼层
上一主题 下一主题
收起左侧

Facebook(1) : 简单的计算程序

 
🔗
darksteel 2012-4-11 07:15:26 | 只看该作者
全局:
本帖最后由 darksteel 于 2012-4-11 07:16 编辑

回复 20# wwwyhx
对,上面15楼提到这个问题,后来也提到通过加参数来解决。
隔了这么长时间回头之前的代码还是有很多不理想的地方。现在稍做改动再贴一下,不知还有没有别的问题,供参考。

  1. #include <iostream>
  2. #include <cstdio>
  3. using namespace std;
  4. char c;
  5. char get()
  6. {
  7.         while((c = cin.get()) == ' ');
  8.         return c;
  9. }
  10. double num()
  11. {
  12.         double ret = 0, dec = 0.1;
  13.         int f = 1;
  14.         if((c = get()) == '-') f = -1;
  15.         else cin.putback(c);
  16.         while(c = get()) {
  17.                 if(c >= '0' && c <= '9')
  18.                         ret = ret * 10 + c - '0';
  19.                 else break;
  20.         }
  21.         if(c != '.') return ret * f;
  22.         while(c = get()) {
  23.                 if(c >= '0' && c <= '9') {
  24.                         ret += dec * (c - '0');
  25.                         dec /= 10;
  26.                 }
  27.                 else break;
  28.         }
  29.         return ret * f;
  30. }
  31. double calc_add(double, int);
  32. double calc_mul(double a, int op)
  33. {
  34.         double ret;
  35.         c = get();
  36.         if(c == '(') {
  37.                 ret = calc_add(0, 1);
  38.                 c=get();
  39.         } else {
  40.                 cin.putback(c);
  41.                 ret = num();
  42.         }
  43.         ret = (op ? a * ret : a / ret);
  44.         if(c == '*' || c == '/')
  45.                 return calc_mul(ret, (c == '*' ? 1 : 0));
  46.         return ret;
  47. }
  48. double calc_add(double a, int op)
  49. {
  50.         double ret = calc_mul(1, 1);
  51.         ret = (op ? a + ret : a - ret);
  52.         if(c == '+' || c == '-')
  53.                 return calc_add(ret, (c == '+' ? 1 : 0));
  54.         return ret;
  55. }
  56. int main()
  57. {
  58.         cout << calc_add(0, 1) << endl;
  59.         return 0;
  60. }
复制代码
回复

使用道具 举报

🔗
 楼主| wwwyhx 2012-4-11 08:54:38 | 只看该作者
全局:
回复  wwwyhx
对,上面15楼提到这个问题,后来也提到通过加参数来解决。
隔了这么长时间回头之前的代码还是有很多不理想的地方。现在稍做改动再贴一下,不知还有没有别的问题,供参考。
darksteel 发表于 2012-4-11 07:15



    其实是编译原理的一个递归下降语法分析, 可以用在稍稍复杂的情况, 列出语法规则直接写程序, 左结合不需要参数可以用迭代的办法实现,比如下面这个:

  1. //implement like a+b*(2-c)

  2. //Top down parser, the correct expression is the first step
  3. //add = mul [+ or - mul]*
  4. //mul = factor [* or / factor]*
  5. //factor = numeric or (add) or (+ or - factor)

  6. //notice: use reference for all parameter
  7. int add(const char*& p);
  8. int mul(const char*& p);
  9. int factor(const char*& p);
  10. int numeric(const char*& p);

  11. void skipblank(const char*& p)
  12. {
  13.         while (*p == ' ')
  14.                 p++;
  15. }

  16. int add(const char*& p)
  17. {
  18.         skipblank(p);

  19.         int nRet = mul(p);
  20.         skipblank(p);

  21.         while (*p == '+' || *p == '-')
  22.         {
  23.                 if (*p == '+')
  24.                         nRet += mul(++p); //should be ++p not p++, otherwise, compile error
  25.                 else nRet -= mul(++p);
  26.                 skipblank(p);
  27.         }

  28.         return nRet;
  29. }

  30. int mul(const char*& p)
  31. {
  32.         skipblank(p);

  33.         int nRet = factor(p);
  34.         skipblank(p);

  35.         //you can't use recursion like "* or / mul" here, if will calculate from the right.
  36.         //E.g consider 2*3/4, if recursive method like "* or / mul" is used, it will calculate
  37.         //"3/4" first which result is 0, and then calculate 2*0 == 0. However, it should be
  38.         //2*3 first == 6 and then 6/4 which is 1
  39.         while (*p == '*' || *p == '/')
  40.         {
  41.                 if (*p == '*')
  42.                         nRet *= factor(++p);
  43.                 else nRet /= factor(++p);
  44.                 skipblank(p);
  45.         }

  46.         return nRet;
  47. }

  48. int factor(const char*& p)
  49. {
  50.         skipblank(p);

  51.         int nRet = 0;
  52.         if (*p == '(')
  53.         {
  54.                 p++;
  55.                 nRet = add(p);
  56.                 skipblank(p);
  57.                 if (*p == ')')
  58.                         p++;
  59.         }
  60.         else if (*p == '+' || *p == '-')
  61.         {
  62.                 bool bNeg = *p == '-';
  63.                 p++;
  64.                 nRet = factor(p);
  65.                 if (bNeg) nRet = -nRet;
  66.         }
  67.         else
  68.                 nRet = numeric(p);

  69.         return nRet;
  70. }

  71. int numeric(const char*& p)
  72. {
  73.         skipblank(p);

  74.         int nRet = 0;
  75.         while (*p >= '0' && *p <= '9')
  76.         {
  77.                 nRet = (*p - '0') + nRet * 10;
  78.                 p++;
  79.         }

  80.         return nRet;
  81. }
复制代码
回复

使用道具 举报

🔗
secretgu 2012-4-11 10:02:53 | 只看该作者
全局:
半个小时写了一把,基本case都ok(如果发现什么case不行请拍砖),等会儿再爬楼看各位前辈的讨论~
  1. #include <iostream>
  2. #include <cstdlib>
  3. #include <stack>

  4. using namespace std;

  5. bool priority_equal_higher(char stop, char newop) {
  6.         if (stop == '*' || stop == '/') return true;
  7.         else if (newop == '+' || newop == '-') return true;
  8.         else return false;
  9. }

  10. int calc(char op, int op1, int op2) {
  11.         if (op == '*') return op1 * op2;
  12.         else if (op == '/') return op1 / op2;
  13.         else if (op == '+') return op1 + op2;
  14.         else return op1 - op2;
  15. }

  16. int main() {
  17.         string input;
  18.         cout << "please input an expression: ";
  19.         cin >> input;
  20.         cout << "your input: " << input << endl;

  21.         stack<int> operands;
  22.         stack<char> operators;
  23.         for (int i = 0; i < input.size();) {
  24.                 if (input[i] >= '0' && input[i] <= '9') {
  25.                         int start = i++;
  26.                         while (i < input.size() && (input[i] >= '0' && input[i] <= '9'))
  27.                                 ++i;
  28.                         operands.push(atoi(input.substr(start, i - start).c_str()));
  29.                 } else {
  30.                         while (operators.empty() == false
  31.                                 && priority_equal_higher(operators.top(), input[i]) == true) {
  32.                                 int op1 = operands.top();
  33.                                 operands.pop();
  34.                                 int op2 = operands.top();
  35.                                 operands.pop();
  36.                                 char op = operators.top();
  37.                                 operators.pop();
  38.                                 int res = calc(op, op2, op1);
  39.                                 operands.push(res);
  40.                         }
  41.                         operators.push(input[i++]);
  42.                 }
  43.         }
  44.         while (operators.empty() == false) {
  45.                 int op1 = operands.top();
  46.                 operands.pop();
  47.                 int op2 = operands.top();
  48.                 operands.pop();
  49.                 char op = operators.top();
  50.                 operators.pop();
  51.                 int res = calc(op, op2, op1);
  52.                 operands.push(res);
  53.         }
  54.         cout << "res: " << operands.top() << endl;
  55.         operands.pop() ;
  56.         return 0;
  57. }
复制代码
回复

使用道具 举报

🔗
darksteel 2012-4-11 11:40:34 | 只看该作者
全局:
回复 22# wwwyhx
嗯,这种跟文法有点相关的都可以这么递归的调来调去。以前做题的时候看见有些人能直接写成迭代的形式,应该得想的比较清楚才行,因为递归总是更容易想一些。
大体方法有了结合性就好解决了,你这个也是一种办法
回复

使用道具 举报

🔗
danielgao 2012-4-17 13:36:56 | 只看该作者
全局:
这题好像可以转成前缀表达式,然后慢慢搞就行了
回复

使用道具 举报

🔗
eastflag 2012-4-17 20:28:24 | 只看该作者
全局:
本帖最后由 eastflag 于 2012-4-17 20:35 编辑

弱弱地传个代码,最傻的办法,一步步算。。。(java)
对了,这里的code不支持java吗?

  1. import java.util.LinkedList;
  2. import java.util.regex.Matcher;
  3. import java.util.regex.Pattern;

  4. public class Arithmetic{
  5. public static void main(String[] args){
  6.   String input = new String("1- 2*3+ 6/3");
  7.   System.out.println(arith(input));
  8. }

  9. private static int arith(String input){
  10.   String str = input.replaceAll("\\s+", "");
  11.   String[] dataStrList = str.split("[\\+\\-\\*\\/]");
  12.   LinkedList<Integer> dataLink = new LinkedList<Integer>();
  13.   for (String tempStr : dataStrList){
  14.    dataLink.add(Integer.valueOf(tempStr));
  15.   }
  16.   
  17.   String[] signStrList = str.split("\\d+");
  18.   StringBuffer signs = new StringBuffer();
  19.   for (String signStr : signStrList){
  20.    signs.append(signStr);
  21.   }
  22.   
  23.   Pattern p = Pattern.compile("[\\*\\/]");
  24.   Matcher m = p.matcher(signs);
  25.   while (m.find()){
  26.    if (signs.charAt(m.start()) == '*'){
  27.     dataLink.add(m.start(),
  28.       dataLink.get(m.start()) * dataLink.get(m.start() + 1));
  29.    }else{
  30.     dataLink.add(m.start(),
  31.       dataLink.get(m.start()) / dataLink.get(m.start() + 1));
  32.    }
  33.    signs.deleteCharAt(m.start());
  34.    dataLink.remove(m.start() + 1);
  35.    dataLink.remove(m.start() + 1);
  36.    m = p.matcher(signs);
  37.   }
  38.   
  39.   int result = dataLink.get(0);
  40.   for (int i = 0; i < signs.length(); i++){
  41.    int sg = 1;
  42.    if (signs.charAt(i) == '-') {
  43.     sg = -1;
  44.    }
  45.    result += sg * dataLink.get(i + 1);
  46.   }
  47.   
  48.   return result;
  49. }
  50. }


复制代码
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册账号
隐私提醒:
  • ☑ 禁止发布广告,拉群,贴个人联系方式:找人请去🔗同学同事飞友,拉群请去🔗拉群结伴,广告请去🔗跳蚤市场,和 🔗租房广告|找室友
  • ☑ 论坛内容在发帖 30 分钟内可以编辑,过后则不能删帖。为防止被骚扰甚至人肉,不要公开留微信等联系方式,如有需求请以论坛私信方式发送。
  • ☑ 干货版块可免费使用 🔗超级匿名:面经(美国面经、中国面经、数科面经、PM面经),抖包袱(美国、中国)和录取汇报、定位选校版
  • ☑ 查阅全站 🔗各种匿名方法

本版积分规则

>
快速回复 返回顶部 返回列表