表达式求值算法、rpn、1470、1475、1477、1479

以下为表达式求值系列完整算法,借用C++语言,读者不妨对照下图表达式求值算法实例,仔细推敲。

  1 /*
  2 DATA:2015 1 30
  3 From:13420228
  4 */
  5 //测试数据:
  6 // 4
  7 // (0!+1)*2^(3!+4) - (5! - 67 - (8+9))
  8 // (1+2)*3+4*5
  9 // 1.000 + 2 / 4
 10 // ((1+2)*5+1)/(4^2)*3
 11 #include <iostream>
 12 #include <cstdlib>
 13 #include <cstring>
 14 #include <stack>
 15 #include <cmath>
 16 using namespace std;
 17 #define N_OPTR 9 //运算符总数
 18 typedef enum { ADD, SUB, MUL, DIV, POW, FAC, L_P, R_P, EOE } Operator; //运算符集合
 19 //加、减、乘、除、乘方、阶乘、左括号、右括号、起始符与终止符
 20 const char pri[N_OPTR][N_OPTR] = { //运算符优先等级 [栈顶] [当前]
 21    /*              |-------------------- 当 前 运 算 符 --------------------| */
 22    /*              +      -      *      /      ^      !      (      )      \0 */
 23    /* --  + */    ‘>‘,   ‘>‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘>‘,   ‘>‘,
 24    /* |   - */    ‘>‘,   ‘>‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘>‘,   ‘>‘,
 25    /* 栈  * */    ‘>‘,   ‘>‘,   ‘>‘,   ‘>‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘>‘,   ‘>‘,
 26    /* 顶  / */    ‘>‘,   ‘>‘,   ‘>‘,   ‘>‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘>‘,   ‘>‘,
 27    /* 运  ^ */    ‘>‘,   ‘>‘,   ‘>‘,   ‘>‘,   ‘>‘,   ‘<‘,   ‘<‘,   ‘>‘,   ‘>‘,
 28    /* 算  ! */    ‘>‘,   ‘>‘,   ‘>‘,   ‘>‘,   ‘>‘,   ‘>‘,   ‘ ‘,   ‘>‘,   ‘>‘,
 29    /* 符  ( */    ‘<‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘=‘,   ‘ ‘,
 30    /* |   ) */    ‘ ‘,   ‘ ‘,   ‘ ‘,   ‘ ‘,   ‘ ‘,   ‘ ‘,   ‘ ‘,   ‘ ‘,   ‘ ‘,
 31    /* -- \0 */    ‘<‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘ ‘,   ‘=‘
 32 };
 33
 34 Operator optr2rank ( char op ) { //由运算符转译出编号
 35    switch ( op ) {
 36       case ‘+‘ : return ADD; //加
 37       case ‘-‘ : return SUB; //减
 38       case ‘*‘ : return MUL; //乘
 39       case ‘/‘ : return DIV; //除
 40       case ‘^‘ : return POW; //乘方
 41       case ‘!‘ : return FAC; //阶乘
 42       case ‘(‘ : return L_P; //左括号
 43       case ‘)‘ : return R_P; //右括号
 44       case ‘\0‘: return EOE; //起始符与终止符
 45       default  : exit ( -1 ); //未知运算符
 46    }
 47 }
 48 char orderBetween ( char op1, char op2 ) //比较两个运算符之间的优先级
 49 { return pri[optr2rank ( op1 ) ][optr2rank ( op2 ) ]; }
 50
 51 char* removeSpace ( char* s ) { //剔除s[]中的白空格
 52    char* p = s, *q = s;
 53    while ( true ) {
 54       while ( isspace ( *q ) ) q++;
 55       if ( ‘\0‘ == *q ) { *p = ‘\0‘; return s; }
 56       *p++ = *q++;
 57    }
 58 }
 59
 60 void readNumber ( char*& p, stack<float>& stk ) { //将起始于p的子串解析为数值,并存入操作数栈
 61    stk.push ( ( float ) ( *p - ‘0‘ ) ); //当前数位对应的数值进栈
 62    while ( isdigit ( * ( ++p ) ) ){ //只要后续还有紧邻的数字(即多位整数的情况),则
 63       float temp=stk.top() * 10 + ( *p - ‘0‘ );stk.pop();stk.push (temp );//弹出原操作数并追加新数位后,新数值重新入栈
 64   }
 65    if ( ‘.‘ != *p ) return; //此后非小数点,则意味着当前操作数解析完成
 66    float fraction = 1; //否则,意味着还有小数部分
 67    while ( isdigit ( * ( ++p ) ) ) {//逐位加入
 68     float temp=stk.top() + ( *p - ‘0‘ ) * ( fraction /= 10 );
 69     stk.pop();
 70     stk.push (temp); //小数部分
 71     }
 72 }
 73
 74 __int64 facI ( int n ) { __int64 f = 1; while ( n > 1 ) f *= n--; return f; } //阶乘运算(迭代版)
 75
 76 void append ( char*& rpn, float opnd ) { //将操作数接至RPN末尾 针对浮点数和字符,分删重轲一个接口
 77    int n = strlen ( rpn ); //RPN当前长度(以‘\0‘结尾,长度n + 1)
 78    char buf[64];
 79    if ( opnd != ( float ) ( int ) opnd ) sprintf ( buf, "%.2f \0", opnd ); //浮点格式,或
 80    else                          sprintf ( buf, "%d \0", ( int ) opnd ); //整数格式
 81    rpn = ( char* ) realloc ( rpn, sizeof ( char ) * ( n + strlen ( buf ) + 1 ) ); //扩展空间
 82    strcat ( rpn, buf ); //RPN加长
 83 }
 84 void append ( char*& rpn, char optr ) { //将运算符接至RPN末尾
 85    int n = strlen ( rpn ); //RPN当前长度(以‘\0‘结尾,长度n + 1)
 86    rpn = ( char* ) realloc ( rpn, sizeof ( char ) * ( n + 3 ) ); //扩展空间
 87    sprintf ( rpn + n, "%c ", optr ); rpn[n + 2] = ‘\0‘; //接入指定的运算符
 88 }
 89
 90 float calcu ( float a, char op, float b ) { //执行二元运算
 91    switch ( op ) {
 92       case ‘+‘ : return a + b;
 93       case ‘-‘ : return a - b;
 94       case ‘*‘ : return a * b;
 95       case ‘/‘ : if ( 0==b ) exit ( -1 ); return a/b; //注意:如此判浮点数为零可能不安全
 96       case ‘^‘ : return pow ( a, b );
 97       default  : exit ( -1 );
 98    }
 99 }
100 float calcu ( char op, float b ) { //执行一元运算
101    switch ( op ) {
102       case ‘!‘ : return ( float ) facI ( ( int ) b ); //目前仅有阶乘,可照此方式添加
103       default  : exit ( -1 );
104    }
105 }
106
107 void print(stack<float> opndStk){
108    printf("opndStk:\n");
109    while(!opndStk.empty()){
110       printf("%.3f ",opndStk.top());
111       opndStk.pop();
112    }
113 }
114 void print(stack<char> optrStk){
115    printf("optrStk:\n");
116    while(!optrStk.empty()){
117       printf("%c ",optrStk.top());
118       optrStk.pop();
119    }
120 }
121 void displayProgress ( char* expr, char* pCh, stack<float>& opndStk, stack<char>& optrStk, char* rpn ) {//  * 显示表达式处理进展
122    system ( "cls" );
123    printf ( "\nexpr:" );
124    for ( char* p = expr; ‘\0‘ != *p; p++ ) printf ( " %c", *p ); printf ( " $\nexpr:" );
125    for ( char* p = expr; p < pCh; p++ ) printf ( "  " );
126    if ( ‘\0‘ != * ( pCh - 1 ) )
127       { for ( char* p = pCh; ‘\0‘ != *p; p++ ) printf ( " %c", *p ); printf ( " $" ); }
128    printf ( "\nexpr:" );
129    for ( char* p = expr; p < pCh; p++ ) printf ( "--" ); printf ( " ^\n\n" );
130    print ( optrStk ); printf ( "\n" );
131    print ( opndStk ); printf ( "\n" );
132    printf ( "RPN:\n %s\n\n", rpn ); //输出RPN
133    getchar();
134 }
135 float evaluate ( char* S, char*& RPN ) { //对(已剔除白空格的)表达式S求值,并转换为逆波兰式RPN
136    stack<float> opnd; stack<char> optr; //运算数栈、运算符栈 /*DSA*/任何时刻,其中每对相邻元素之间均大小一致
137    /*DSA*/ char* expr = S;
138    optr.push ( ‘\0‘ ); //尾哨兵‘\0‘也作为头哨兵首先入栈
139    while ( !optr.empty() ) { //在运算符栈非空之前,逐个处理表达式中各字符
140       if ( isdigit ( *S ) ) { //若当前字符为操作数,则
141          readNumber ( S, opnd ); append ( RPN, opnd.top() ); //读入操作数,并将其接至RPN末尾
142       } else //若当前字符为运算符,则
143          switch ( orderBetween ( optr.top(), *S ) ) { //视其与栈顶运算符之间优先级高低分别处理
144             case ‘<‘: //栈顶运算符优先级更低时
145                optr.push ( *S ); S++; //计算推迟,当前运算符进栈
146                break;
147             case ‘=‘: //优先级相等(当前运算符为右括号或者尾部哨兵‘\0‘)时
148                optr.pop(); S++; //脱括号并接收下一个字符
149                break;
150             case ‘>‘: { //栈顶运算符优先级更高时,可实施相应的计算,并将结果重新入栈
151                char op = optr.top(); optr.pop();append ( RPN, op ); //栈顶运算符出栈并续接至RPN末尾
152                if ( ‘!‘ == op ) { //若属于一元运算符
153                   float pOpnd = opnd.top();opnd.pop(); //只需取出一个操作数,并
154                   opnd.push ( calcu ( op, pOpnd ) ); //实施一元计算,结果入栈
155                } else { //对于其它(二元)运算符
156                   float pOpnd2 = opnd.top();opnd.pop();
157                   float pOpnd1 = opnd.top();opnd.pop(); //取出后、前操作数 /*DSA*/提问:可否省去两个临时变量?
158                   opnd.push ( calcu ( pOpnd1, op, pOpnd2 ) ); //实施二元计算,结果入栈
159                }
160                break;
161             }
162             default : exit ( -1 ); //逢语法错误,不做处理直接退出
163          }//switch
164       displayProgress ( expr, S, opnd, optr, RPN );
165    }//while
166    float temp=opnd.top();opnd.pop();
167    return temp; //弹出并返回最后的计算结果
168 }
169 int main ( int argc, char* argv[] ) {
170    //freopen("input.txt","r",stdin);
171    int n;
172    printf("||====================================================||\n");
173    printf("||******************表达式求值************************||\n");
174    printf("||***支持加、减、乘、除、乘方、阶乘、左括号、右括号***||\n");
175    printf("||====================================================||\n");
176
177    printf ( "\nplease scanf the number of evaluate:\n" );
178    scanf("%d",&n);
179    getchar();//处理第一行末的‘\n‘
180    while(n--)
181    {
182       char str[100];
183       system ( "cls" );
184       printf ( "\nplease scanf the evaluate:\n" );
185       gets(str);//表达式求值(入口)
186       printf ( "\nPress [Enter] key to evaluate: [%s]\n", str );getchar();
187       char* rpn = ( char* ) malloc ( sizeof ( char ) * 1 );   rpn[0] = ‘\0‘; //逆波兰表达式
188       float value = evaluate ( removeSpace ( str ), rpn ); //求值
189       printf ( "EXPR\t: %s\n", str ); //输出原表达式
190       printf ( "RPN\t: [ %s]\n", rpn ); //输出RPN
191       printf ( "Value\t= %.3f = %d\n", value, ( int ) value ); //输出表达式的值
192       free ( rpn );   rpn = NULL;
193       getchar();
194    }
195    return 0;
196 }

显然,对以上算法稍加修改,即可得出:

1475:表达式的计算1:

  1 // 3+2+1
  2 // 3-2-1
  3 // 1+2*3
  4 // 0
  5
  6 #include <iostream>
  7 #include <cstdlib>
  8 #include <cstring>
  9 #include <stack>
 10 #include <cmath>
 11 using namespace std;
 12 #define N_OPTR 9 //运算符总数
 13 typedef enum { ADD, SUB, MUL, DIV, POW, FAC, L_P, R_P, EOE } Operator; //运算符集合
 14 //加、减、乘、除、乘方、阶乘、左括号、右括号、起始符与终止符
 15 const char pri[N_OPTR][N_OPTR] = { //运算符优先等级 [栈顶] [当前]
 16    /*              |-------------------- 当 前 运 算 符 --------------------| */
 17    /*              +      -      *      /      ^      !      (      )      \0 */
 18    /* --  + */    ‘>‘,   ‘>‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘>‘,   ‘>‘,
 19    /* |   - */    ‘>‘,   ‘>‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘>‘,   ‘>‘,
 20    /* 栈  * */    ‘>‘,   ‘>‘,   ‘>‘,   ‘>‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘>‘,   ‘>‘,
 21    /* 顶  / */    ‘>‘,   ‘>‘,   ‘>‘,   ‘>‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘>‘,   ‘>‘,
 22    /* 运  ^ */    ‘>‘,   ‘>‘,   ‘>‘,   ‘>‘,   ‘>‘,   ‘<‘,   ‘<‘,   ‘>‘,   ‘>‘,
 23    /* 算  ! */    ‘>‘,   ‘>‘,   ‘>‘,   ‘>‘,   ‘>‘,   ‘>‘,   ‘ ‘,   ‘>‘,   ‘>‘,
 24    /* 符  ( */    ‘<‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘=‘,   ‘ ‘,
 25    /* |   ) */    ‘ ‘,   ‘ ‘,   ‘ ‘,   ‘ ‘,   ‘ ‘,   ‘ ‘,   ‘ ‘,   ‘ ‘,   ‘ ‘,
 26    /* -- \0 */    ‘<‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘ ‘,   ‘=‘
 27 };
 28
 29 void readNumber ( char*& p, stack<float>& stk ) { //将起始于p的子串解析为数值,并存入操作数栈
 30    stk.push ( ( float ) ( *p - ‘0‘ ) ); //当前数位对应的数值进栈
 31    while ( isdigit ( * ( ++p ) ) ){ //只要后续还有紧邻的数字(即多位整数的情况),则
 32       float temp=stk.top() * 10 + ( *p - ‘0‘ );stk.pop();stk.push (temp );//弹出原操作数并追加新数位后,新数值重新入栈
 33   }
 34    if ( ‘.‘ != *p ) return; //此后非小数点,则意味着当前操作数解析完成
 35    float fraction = 1; //否则,意味着还有小数部分
 36    while ( isdigit ( * ( ++p ) ) ) {//逐位加入
 37     float temp=stk.top() + ( *p - ‘0‘ ) * ( fraction /= 10 );
 38     stk.pop();
 39     stk.push (temp); //小数部分
 40     }
 41 }
 42
 43 void append ( char*& rpn, float opnd ) { //将操作数接至RPN末尾
 44    int n = strlen ( rpn ); //RPN当前长度(以‘\0‘结尾,长度n + 1)
 45    char buf[64];
 46    if ( opnd != ( float ) ( int ) opnd ) sprintf ( buf, "%.2f \0", opnd ); //浮点格式,或
 47    else                          sprintf ( buf, "%d\0", ( int ) opnd ); //整数格式
 48    rpn = ( char* ) realloc ( rpn, sizeof ( char ) * ( n + strlen ( buf ) + 1 ) ); //扩展空间
 49    strcat ( rpn, buf ); //RPN加长
 50 }
 51
 52 void append ( char*& rpn, char optr ) { //将运算符接至RPN末尾
 53    int n = strlen ( rpn ); //RPN当前长度(以‘\0‘结尾,长度n + 1)
 54    rpn = ( char* ) realloc ( rpn, sizeof ( char ) * ( n + 3 ) ); //扩展空间
 55    sprintf ( rpn + n, "%c", optr ); rpn[n + 2] = ‘\0‘; //接入指定的运算符
 56 }
 57
 58 Operator optr2rank ( char op ) { //由运算符转译出编号
 59    switch ( op ) {
 60       case ‘+‘ : return ADD; //加
 61       case ‘-‘ : return SUB; //减
 62       case ‘*‘ : return MUL; //乘
 63       case ‘/‘ : return DIV; //除
 64       case ‘^‘ : return POW; //乘方
 65       case ‘!‘ : return FAC; //阶乘
 66       case ‘(‘ : return L_P; //左括号
 67       case ‘)‘ : return R_P; //右括号
 68       case ‘\0‘: return EOE; //起始符与终止符
 69       default  : exit ( -1 ); //未知运算符
 70    }
 71 }
 72
 73 char orderBetween ( char op1, char op2 ) //比较两个运算符之间的优先级
 74 { return pri[optr2rank ( op1 ) ][optr2rank ( op2 ) ]; }
 75
 76
 77 __int64 facI ( int n ) { __int64 f = 1; while ( n > 1 ) f *= n--; return f; } //阶乘运算(迭代版)
 78
 79 float calcu ( float a, char op, float b ) { //执行二元运算
 80    switch ( op ) {
 81       case ‘+‘ : return a + b;
 82       case ‘-‘ : return a - b;
 83       case ‘*‘ : return a * b;
 84       case ‘/‘ : if ( 0==b ) exit ( -1 ); return a/b; //注意:如此判浮点数为零可能不安全
 85       case ‘^‘ : return pow ( a, b );
 86       default  : exit ( -1 );
 87    }
 88 }
 89 float calcu ( char op, float b ) { //执行一元运算
 90    switch ( op ) {
 91       case ‘!‘ : return ( float ) facI ( ( int ) b ); //目前仅有阶乘,可照此方式添加
 92       default  : exit ( -1 );
 93    }
 94 }
 95
 96 float evaluate ( char* S, char*& RPN ) { //对(已剔除白空格的)表达式S求值,并转换为逆波兰式RPN
 97    stack<float> opnd; stack<char> optr; //运算数栈、运算符栈 /*DSA*/任何时刻,其中每对相邻元素之间均大小一致
 98    /*DSA*/ char* expr = S;
 99    optr.push ( ‘\0‘ ); //尾哨兵‘\0‘也作为头哨兵首先入栈
100    while ( !optr.empty() ) { //在运算符栈非空之前,逐个处理表达式中各字符
101       if ( isdigit ( *S ) ) { //若当前字符为操作数,则
102          readNumber ( S, opnd ); append ( RPN, opnd.top() ); //读入操作数,并将其接至RPN末尾
103       } else //若当前字符为运算符,则
104          switch ( orderBetween ( optr.top(), *S ) ) { //视其与栈顶运算符之间优先级高低分别处理
105             case ‘<‘: //栈顶运算符优先级更低时
106                optr.push ( *S ); S++; //计算推迟,当前运算符进栈
107                break;
108             case ‘=‘: //优先级相等(当前运算符为右括号或者尾部哨兵‘\0‘)时
109                optr.pop(); S++; //脱括号并接收下一个字符
110                break;
111             case ‘>‘: { //栈顶运算符优先级更高时,可实施相应的计算,并将结果重新入栈
112                char op = optr.top(); optr.pop();append ( RPN, op ); //栈顶运算符出栈并续接至RPN末尾
113                if ( ‘!‘ == op ) { //若属于一元运算符
114                   float pOpnd = opnd.top();opnd.pop(); //只需取出一个操作数,并
115                   opnd.push ( calcu ( op, pOpnd ) ); //实施一元计算,结果入栈
116                } else { //对于其它(二元)运算符
117                   float pOpnd2 = opnd.top();opnd.pop();
118                   float pOpnd1 = opnd.top();opnd.pop(); //取出后、前操作数 /*DSA*/提问:可否省去两个临时变量?
119                   opnd.push ( calcu ( pOpnd1, op, pOpnd2 ) ); //实施二元计算,结果入栈
120                }
121                break;
122             }
123             default : exit ( -1 ); //逢语法错误,不做处理直接退出
124          }//switch
125       /*DSA*///displayProgress ( expr, S, opnd, optr, RPN );
126    }//while
127    float temp=opnd.top();opnd.pop();
128    return temp; //弹出并返回最后的计算结果
129 }
130 char* removeSpace ( char* s ) { //剔除s[]中的白空格
131    char* p = s, *q = s;
132    while ( true ) {
133       while ( isspace ( *q ) ) q++;
134       if ( ‘\0‘ == *q ) { *p = ‘\0‘; return s; }
135       *p++ = *q++;
136    }
137 }
138 int main ( int argc, char* argv[] ) { //表达式求值(入口)
139    // freopen("input.txt","r",stdin);
140    while(true)
141    {
142       char str[100];
143       gets(str);
144       if(str[0]==‘0‘) break;
145    //for ( int i = 0; i < strlen(str); i++ ) { //逐一处理各命令行参数(表达式)
146       ///*DSA*/system ( "cls" ); //
147    //printf ( "\nPress any key to evaluate: [%s]\n", str );
148       char* rpn = ( char* ) malloc ( sizeof ( char ) * 1 );   rpn[0] = ‘\0‘; //逆波兰表达式
149       float value = evaluate ( removeSpace ( str ), rpn ); //求值
150       ///*DSA*/printf ( "EXPR\t: %s\n", str ); //输出原表达式
151       ///*DSA*/printf ( "%s\n", rpn ); //输出RPN
152       /*DSA*/printf ( "%d\n",( int ) value ); //输出表达式的值
153       free ( rpn );   rpn = NULL;
154    }
155    return 0;
156 }

1477:中缀转换成后缀:

  1 //测试用例:
  2 // 2
  3 // 1+2
  4 // (1+2)*3+4*5
  5
  6 #include <iostream>
  7 #include <cstdlib>
  8 #include <cstring>
  9 #include <stack>
 10 #include <cmath>
 11 using namespace std;
 12 #define N_OPTR 9 //运算符总数
 13 typedef enum { ADD, SUB, MUL, DIV, POW, FAC, L_P, R_P, EOE } Operator; //运算符集合
 14 //加、减、乘、除、乘方、阶乘、左括号、右括号、起始符与终止符
 15 const char pri[N_OPTR][N_OPTR] = { //运算符优先等级 [栈顶] [当前]
 16    /*              |-------------------- 当 前 运 算 符 --------------------| */
 17    /*              +      -      *      /      ^      !      (      )      \0 */
 18    /* --  + */    ‘>‘,   ‘>‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘>‘,   ‘>‘,
 19    /* |   - */    ‘>‘,   ‘>‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘>‘,   ‘>‘,
 20    /* 栈  * */    ‘>‘,   ‘>‘,   ‘>‘,   ‘>‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘>‘,   ‘>‘,
 21    /* 顶  / */    ‘>‘,   ‘>‘,   ‘>‘,   ‘>‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘>‘,   ‘>‘,
 22    /* 运  ^ */    ‘>‘,   ‘>‘,   ‘>‘,   ‘>‘,   ‘>‘,   ‘<‘,   ‘<‘,   ‘>‘,   ‘>‘,
 23    /* 算  ! */    ‘>‘,   ‘>‘,   ‘>‘,   ‘>‘,   ‘>‘,   ‘>‘,   ‘ ‘,   ‘>‘,   ‘>‘,
 24    /* 符  ( */    ‘<‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘=‘,   ‘ ‘,
 25    /* |   ) */    ‘ ‘,   ‘ ‘,   ‘ ‘,   ‘ ‘,   ‘ ‘,   ‘ ‘,   ‘ ‘,   ‘ ‘,   ‘ ‘,
 26    /* -- \0 */    ‘<‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘ ‘,   ‘=‘
 27 };
 28
 29 void readNumber ( char*& p, stack<float>& stk ) { //将起始于p的子串解析为数值,并存入操作数栈
 30    stk.push ( ( float ) ( *p - ‘0‘ ) ); //当前数位对应的数值进栈
 31    while ( isdigit ( * ( ++p ) ) ){ //只要后续还有紧邻的数字(即多位整数的情况),则
 32       float temp=stk.top() * 10 + ( *p - ‘0‘ );stk.pop();stk.push (temp );//弹出原操作数并追加新数位后,新数值重新入栈
 33   }
 34    if ( ‘.‘ != *p ) return; //此后非小数点,则意味着当前操作数解析完成
 35    float fraction = 1; //否则,意味着还有小数部分
 36    while ( isdigit ( * ( ++p ) ) ) {//逐位加入
 37     float temp=stk.top() + ( *p - ‘0‘ ) * ( fraction /= 10 );
 38     stk.pop();
 39     stk.push (temp); //小数部分
 40     }
 41 }
 42
 43 void append ( char*& rpn, float opnd ) { //将操作数接至RPN末尾
 44    int n = strlen ( rpn ); //RPN当前长度(以‘\0‘结尾,长度n + 1)
 45    char buf[64];
 46    if ( opnd != ( float ) ( int ) opnd ) sprintf ( buf, "%.2f\0", opnd ); //浮点格式,或
 47    else                          sprintf ( buf, "%d\0", ( int ) opnd ); //整数格式
 48    rpn = ( char* ) realloc ( rpn, sizeof ( char ) * ( n + strlen ( buf ) + 1 ) ); //扩展空间
 49    strcat ( rpn, buf ); //RPN加长
 50 }
 51 void append ( char*& rpn, char optr ) { //将运算符接至RPN末尾
 52    int n = strlen ( rpn ); //RPN当前长度(以‘\0‘结尾,长度n + 1)
 53    rpn = ( char* ) realloc ( rpn, sizeof ( char ) * ( n + 3 ) ); //扩展空间
 54    sprintf ( rpn + n, "%c", optr ); rpn[n + 2] = ‘\0‘; //接入指定的运算符
 55 }
 56
 57 Operator optr2rank ( char op ) { //由运算符转译出编号
 58    switch ( op ) {
 59       case ‘+‘ : return ADD; //加
 60       case ‘-‘ : return SUB; //减
 61       case ‘*‘ : return MUL; //乘
 62       case ‘/‘ : return DIV; //除
 63       case ‘^‘ : return POW; //乘方
 64       case ‘!‘ : return FAC; //阶乘
 65       case ‘(‘ : return L_P; //左括号
 66       case ‘)‘ : return R_P; //右括号
 67       case ‘\0‘: return EOE; //起始符与终止符
 68       default  : exit ( -1 ); //未知运算符
 69    }
 70 }
 71
 72 char orderBetween ( char op1, char op2 ) //比较两个运算符之间的优先级
 73 { return pri[optr2rank ( op1 ) ][optr2rank ( op2 ) ]; }
 74
 75
 76 __int64 facI ( int n ) { __int64 f = 1; while ( n > 1 ) f *= n--; return f; } //阶乘运算(迭代版)
 77
 78 float calcu ( float a, char op, float b ) { //执行二元运算
 79    switch ( op ) {
 80       case ‘+‘ : return a + b;
 81       case ‘-‘ : return a - b;
 82       case ‘*‘ : return a * b;
 83       case ‘/‘ : if ( 0==b ) exit ( -1 ); return a/b; //注意:如此判浮点数为零可能不安全
 84       case ‘^‘ : return pow ( a, b );
 85       default  : exit ( -1 );
 86    }
 87 }
 88 float calcu ( char op, float b ) { //执行一元运算
 89    switch ( op ) {
 90       case ‘!‘ : return ( float ) facI ( ( int ) b ); //目前仅有阶乘,可照此方式添加
 91       default  : exit ( -1 );
 92    }
 93 }
 94
 95 float evaluate ( char* S, char*& RPN ) { //对(已剔除白空格的)表达式S求值,并转换为逆波兰式RPN
 96    stack<float> opnd; stack<char> optr; //运算数栈、运算符栈 /*DSA*/任何时刻,其中每对相邻元素之间均大小一致
 97    /*DSA*/ char* expr = S;
 98    optr.push ( ‘\0‘ ); //尾哨兵‘\0‘也作为头哨兵首先入栈
 99    while ( !optr.empty() ) { //在运算符栈非空之前,逐个处理表达式中各字符
100       if ( isdigit ( *S ) ) { //若当前字符为操作数,则
101          readNumber ( S, opnd ); append ( RPN, opnd.top() ); //读入操作数,并将其接至RPN末尾
102       } else //若当前字符为运算符,则
103          switch ( orderBetween ( optr.top(), *S ) ) { //视其与栈顶运算符之间优先级高低分别处理
104             case ‘<‘: //栈顶运算符优先级更低时
105                optr.push ( *S ); S++; //计算推迟,当前运算符进栈
106                break;
107             case ‘=‘: //优先级相等(当前运算符为右括号或者尾部哨兵‘\0‘)时
108                optr.pop(); S++; //脱括号并接收下一个字符
109                break;
110             case ‘>‘: { //栈顶运算符优先级更高时,可实施相应的计算,并将结果重新入栈
111                char op = optr.top(); optr.pop();append ( RPN, op ); //栈顶运算符出栈并续接至RPN末尾
112                if ( ‘!‘ == op ) { //若属于一元运算符
113                   float pOpnd = opnd.top();opnd.pop(); //只需取出一个操作数,并
114                   opnd.push ( calcu ( op, pOpnd ) ); //实施一元计算,结果入栈
115                } else { //对于其它(二元)运算符
116                   float pOpnd2 = opnd.top();opnd.pop();
117                   float pOpnd1 = opnd.top();opnd.pop(); //取出后、前操作数 /*DSA*/提问:可否省去两个临时变量?
118                   opnd.push ( calcu ( pOpnd1, op, pOpnd2 ) ); //实施二元计算,结果入栈
119                }
120                break;
121             }
122             default : exit ( -1 ); //逢语法错误,不做处理直接退出
123          }//switch
124       /*DSA*///displayProgress ( expr, S, opnd, optr, RPN );
125    }//while
126    float temp=opnd.top();opnd.pop();
127    return temp; //弹出并返回最后的计算结果
128 }
129 char* removeSpace ( char* s ) { //剔除s[]中的白空格
130    char* p = s, *q = s;
131    while ( true ) {
132       while ( isspace ( *q ) ) q++;
133       if ( ‘\0‘ == *q ) { *p = ‘\0‘; return s; }
134       *p++ = *q++;
135    }
136 }
137
138 int main ( int argc, char* argv[] ) {
139    // freopen("input.txt","r",stdin);
140    int n;
141    scanf("%d",&n);
142    getchar();
143    while(n--)
144    {
145       char str[100];
146       gets(str);
147    //printf ( "\nPress any key to evaluate: [%s]\n", str );
148       char* rpn = ( char* ) malloc ( sizeof ( char ) * 1 );   rpn[0] = ‘\0‘; //逆波兰表达式
149       float value = evaluate ( removeSpace ( str ), rpn ); //求值
150       ///*DSA*/printf ( "EXPR\t: %s\n", str ); //输出原表达式
151       /*DSA*/printf ( "%s\n", rpn ); //输出RPN
152       ///*DSA*/printf ( "Value\t= %.1f = %d\n", value, ( int ) value ); //输出表达式的值
153       free ( rpn );   rpn = NULL;
154    }
155    return 0;
156 }

1479:表达式的计算2:

  1 //测试用例
  2 // 2
  3 // 1.000+2/4=
  4 // ((1+2)*5+1)/4=
  5 #include <iostream>
  6 #include <cstdlib>
  7 #include <cstring>
  8 #include <stack>
  9 #include <cmath>
 10 using namespace std;
 11 #define N_OPTR 9 //运算符总数
 12 typedef enum { ADD, SUB, MUL, DIV, POW, FAC, L_P, R_P, EOE } Operator; //运算符集合
 13 //加、减、乘、除、乘方、阶乘、左括号、右括号、起始符与终止符
 14 const char pri[N_OPTR][N_OPTR] = { //运算符优先等级 [栈顶] [当前]
 15    /*              |-------------------- 当 前 运 算 符 --------------------| */
 16    /*              +      -      *      /      ^      !      (      )      \0 */
 17    /* --  + */    ‘>‘,   ‘>‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘>‘,   ‘>‘,
 18    /* |   - */    ‘>‘,   ‘>‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘>‘,   ‘>‘,
 19    /* 栈  * */    ‘>‘,   ‘>‘,   ‘>‘,   ‘>‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘>‘,   ‘>‘,
 20    /* 顶  / */    ‘>‘,   ‘>‘,   ‘>‘,   ‘>‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘>‘,   ‘>‘,
 21    /* 运  ^ */    ‘>‘,   ‘>‘,   ‘>‘,   ‘>‘,   ‘>‘,   ‘<‘,   ‘<‘,   ‘>‘,   ‘>‘,
 22    /* 算  ! */    ‘>‘,   ‘>‘,   ‘>‘,   ‘>‘,   ‘>‘,   ‘>‘,   ‘ ‘,   ‘>‘,   ‘>‘,
 23    /* 符  ( */    ‘<‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘=‘,   ‘ ‘,
 24    /* |   ) */    ‘ ‘,   ‘ ‘,   ‘ ‘,   ‘ ‘,   ‘ ‘,   ‘ ‘,   ‘ ‘,   ‘ ‘,   ‘ ‘,
 25    /* -- \0 */    ‘<‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘<‘,   ‘ ‘,   ‘=‘
 26 };
 27
 28 void readNumber ( char*& p, stack<float>& stk ) { //将起始于p的子串解析为数值,并存入操作数栈
 29    stk.push ( ( float ) ( *p - ‘0‘ ) ); //当前数位对应的数值进栈
 30    while ( isdigit ( * ( ++p ) ) ){ //只要后续还有紧邻的数字(即多位整数的情况),则
 31       float temp=stk.top() * 10 + ( *p - ‘0‘ );stk.pop();stk.push (temp );//弹出原操作数并追加新数位后,新数值重新入栈
 32   }
 33    if ( ‘.‘ != *p ) return; //此后非小数点,则意味着当前操作数解析完成
 34    float fraction = 1; //否则,意味着还有小数部分
 35    while ( isdigit ( * ( ++p ) ) ) {//逐位加入
 36     float temp=stk.top() + ( *p - ‘0‘ ) * ( fraction /= 10 );
 37     stk.pop();
 38     stk.push (temp); //小数部分
 39     }
 40 }
 41
 42 void append ( char*& rpn, float opnd ) { //将操作数接至RPN末尾
 43    int n = strlen ( rpn ); //RPN当前长度(以‘\0‘结尾,长度n + 1)
 44    char buf[64];
 45    if ( opnd != ( float ) ( int ) opnd ) sprintf ( buf, "%.2f \0", opnd ); //浮点格式,或
 46    else                          sprintf ( buf, "%d\0", ( int ) opnd ); //整数格式
 47    rpn = ( char* ) realloc ( rpn, sizeof ( char ) * ( n + strlen ( buf ) + 1 ) ); //扩展空间
 48    strcat ( rpn, buf ); //RPN加长
 49 }
 50 void append ( char*& rpn, char optr ) { //将运算符接至RPN末尾
 51    int n = strlen ( rpn ); //RPN当前长度(以‘\0‘结尾,长度n + 1)
 52    rpn = ( char* ) realloc ( rpn, sizeof ( char ) * ( n + 3 ) ); //扩展空间
 53    sprintf ( rpn + n, "%c", optr ); rpn[n + 2] = ‘\0‘; //接入指定的运算符
 54 }
 55
 56 Operator optr2rank ( char op ) { //由运算符转译出编号
 57    switch ( op ) {
 58       case ‘+‘ : return ADD; //加
 59       case ‘-‘ : return SUB; //减
 60       case ‘*‘ : return MUL; //乘
 61       case ‘/‘ : return DIV; //除
 62       case ‘^‘ : return POW; //乘方
 63       case ‘!‘ : return FAC; //阶乘
 64       case ‘(‘ : return L_P; //左括号
 65       case ‘)‘ : return R_P; //右括号
 66       case ‘\0‘: return EOE; //起始符与终止符
 67       default  : exit ( -1 ); //未知运算符
 68    }
 69 }
 70
 71 char orderBetween ( char op1, char op2 ) //比较两个运算符之间的优先级
 72 { return pri[optr2rank ( op1 ) ][optr2rank ( op2 ) ]; }
 73
 74 __int64 facI ( int n ) { __int64 f = 1; while ( n > 1 ) f *= n--; return f; } //阶乘运算(迭代版)
 75
 76 float calcu ( float a, char op, float b ) { //执行二元运算
 77    switch ( op ) {
 78       case ‘+‘ : return a + b;
 79       case ‘-‘ : return a - b;
 80       case ‘*‘ : return a * b;
 81       case ‘/‘ : if ( 0==b ) exit ( -1 ); return a/b; //注意:如此判浮点数为零可能不安全
 82       case ‘^‘ : return pow ( a, b );
 83       default  : exit ( -1 );
 84    }
 85 }
 86
 87 float calcu ( char op, float b ) { //执行一元运算
 88    switch ( op ) {
 89       case ‘!‘ : return ( float ) facI ( ( int ) b ); //目前仅有阶乘,可照此方式添加
 90       default  : exit ( -1 );
 91    }
 92 }
 93
 94 float evaluate ( char* S, char*& RPN ) { //对(已剔除白空格的)表达式S求值,并转换为逆波兰式RPN
 95    stack<float> opnd; stack<char> optr; //运算数栈、运算符栈 /*DSA*/任何时刻,其中每对相邻元素之间均大小一致
 96    /*DSA*/ char* expr = S;
 97    optr.push ( ‘\0‘ ); //尾哨兵‘\0‘也作为头哨兵首先入栈
 98    while ( !optr.empty() ) { //在运算符栈非空之前,逐个处理表达式中各字符
 99       if ( isdigit ( *S ) ) { //若当前字符为操作数,则
100          readNumber ( S, opnd ); append ( RPN, opnd.top() ); //读入操作数,并将其接至RPN末尾
101       } else //若当前字符为运算符,则
102          switch ( orderBetween ( optr.top(), *S ) ) { //视其与栈顶运算符之间优先级高低分别处理
103             case ‘<‘: //栈顶运算符优先级更低时
104                optr.push ( *S ); S++; //计算推迟,当前运算符进栈
105                break;
106             case ‘=‘: //优先级相等(当前运算符为右括号或者尾部哨兵‘\0‘)时
107                optr.pop(); S++; //脱括号并接收下一个字符
108                break;
109             case ‘>‘: { //栈顶运算符优先级更高时,可实施相应的计算,并将结果重新入栈
110                char op = optr.top(); optr.pop();append ( RPN, op ); //栈顶运算符出栈并续接至RPN末尾
111                if ( ‘!‘ == op ) { //若属于一元运算符
112                   float pOpnd = opnd.top();opnd.pop(); //只需取出一个操作数,并
113                   opnd.push ( calcu ( op, pOpnd ) ); //实施一元计算,结果入栈
114                } else { //对于其它(二元)运算符
115                   float pOpnd2 = opnd.top();opnd.pop();
116                   float pOpnd1 = opnd.top();opnd.pop(); //取出后、前操作数 /*DSA*/提问:可否省去两个临时变量?
117                   opnd.push ( calcu ( pOpnd1, op, pOpnd2 ) ); //实施二元计算,结果入栈
118                }
119                break;
120             }
121             default : exit ( -1 ); //逢语法错误,不做处理直接退出
122          }//switch
123       /*DSA*///displayProgress ( expr, S, opnd, optr, RPN );
124    }//while
125    float temp=opnd.top();opnd.pop();
126    return temp; //弹出并返回最后的计算结果
127 }
128
129 char* removeSpace ( char* s ) { //剔除s[]中的白空格
130    char* p = s, *q = s;
131    while ( true ) {
132       while ( isspace ( *q ) ) q++;
133       if ( ‘\0‘ == *q ) { *p = ‘\0‘; return s; }
134       *p++ = *q++;
135    }
136 }
137
138 int main ( int argc, char* argv[] ) { //表达式求值(入口)
139    // freopen("input.txt","r",stdin);
140    int n;
141    scanf("%d",&n);
142    getchar();
143    while(n--)
144    {
145       char str[1001];
146       gets(str);
147       if(str[strlen(str)-1]==‘=‘)  str[strlen(str)-1]=‘\0‘;
148    //for ( int i = 0; i < strlen(str); i++ ) { //逐一处理各命令行参数(表达式)
149       ///*DSA*/system ( "cls" ); //
150    //printf ( "\nPress any key to evaluate: [%s]\n", str );
151       char* rpn = ( char* ) malloc ( sizeof ( char ) * 1 );   rpn[0] = ‘\0‘; //逆波兰表达式
152       float value = evaluate ( removeSpace ( str ), rpn ); //求值
153       ///*DSA*/printf ( "EXPR\t: %s\n", str ); //输出原表达式
154       ///*DSA*/printf ( "%s\n", rpn ); //输出RPN
155       /*DSA*/printf ( "%.2f\n",value ); //输出表达式的值
156       free ( rpn );   rpn = NULL;
157    }
158    return 0;
159 }

附:1470:逆波兰表达式

 1 // 测试用例:
 2 // * - 2 3 4
 3 // - 3 2
 4 // - 7 7
 5 // * + 11.0 12.0 + 24.0 35.0
 6 #include <iostream>
 7 #include <cstdlib>
 8 #include <cmath>
 9 using namespace std;
10 double Evaluate()//波兰(前缀)表达式递归求值算法,需要好好理解
11 {
12     char a[15];//用于存储每次递归读取的一个非空字符(串)
13     if (scanf("%s", &a) == EOF) exit(0);//处理多组数据正常结束的问题
14     switch (a[0])
15     {
16     case ‘+‘: return Evaluate() + Evaluate();
17     case ‘-‘: return Evaluate() - Evaluate();
18     case ‘*‘: return Evaluate() * Evaluate();
19     case ‘/‘: return Evaluate() / Evaluate();
20     default: return atof(a);
21     }
22 }
23 int main(int argc, char const *argv[])
24 {
25     //#ifndef _OJ_  //ONLINE_JUDGE
26     // freopen("input.txt", "r", stdin);
27     // freopen("output.txt", "w", stdout);
28     //#endif
29     while (1)   printf("%f\n",Evaluate());
30     return 0;
31 }

时间: 2024-11-05 22:01:43

表达式求值算法、rpn、1470、1475、1477、1479的相关文章

算法手记(2)Dijkstra双栈算术表达式求值算法

这两天看到的内容是关于栈和队列,在栈的模块发现了Dijkstra双栈算术表达式求值算法,可以用来实现计算器类型的app. 编程语言系统一般都内置了对算术表达式的处理,但是他们是如何在内部实现的呢?为了了解这个过程,我们可以自行搭建一套简易的算术表达式处理机制,这里就用到栈特性和本篇提到的Dijkstra算法. 概述:     算术表达式可能是一个数.或者是由一个左括号.一个算术表达式.一个运算符.另一个算术表达式和一个右括号组成的表达式.为了简化问题,这里定义的是未省略括号的算术表达式,它明确地

Dijkstra的双栈算术表达式求值算法 C++实现

1 #include<iostream> 2 #include<string> 3 using namespace std; 4 5 template<typename T> 6 class Stack 7 { 8 private: 9 T stack[100]; 10 int i = 0; 11 public: 12 Stack() = default; 13 14 T pop() 15 { 16 if (i == -1) 17 { 18 cout <<

栈练习--Dijkstra的双栈算术表达式求值算法

此法还有待完善,比如在做除法运算时未判断除数是否为0,而且也可以加以扩展,比如log.sin.操作符优先级.. 1 public class Evaluate { 2 3 public static void main(String[] args) { 4 String steam = "( 1 + ( 2 + 3 ) * ( 4 * 5 ) ) )"; 5 // String steam = "( ( 1 + sqrt ( 5.0 ) ) / 2.0 )"; 6

Dijkstra的双栈算术表达式求值算法

1 public static double evaluate(String inStr) { 2 Stack<String> ops = new Stack<String>(); //操作符栈 3 Stack<Double> vals = new Stack<Double>(); //操作数栈 4 char[] arr = inStr.toCharArray(); 5 for(char c : arr){ 6 String s =c+""

算法-表达式求值

今天在网上看到Dijkstra双栈算术表达式求值算法,可以用来实现计算器类型的app,以前很早的时候知道通过算术栈和数值栈搞定的,这次用OC通过数组实现了预期的效果,编程语言系统一般都内置了对算术表达式的处理,我们可以简易的模仿一下算术表达式处理机制,思想不变,主要是实现方式略有不同.算术表达式可能是一个数.或者是由一个左括号.一个算术表达式.一个运算符.另一个算术表达式和一个右括号组成的表达式.为了简化问题,这里定义的是未省略括号的算术表达式,它明确地说明了所有运算符的操作数,形式如下:(1+

表达式求值及转换算法

后缀表达式求值算法 stack operands;  //运算数栈 while(没到表达式尾) {     scanf("一个运算对象op");     if(op is 运算数)         operands.push(op);     else if(op is 运算符)     {         operand_right = operands.pop();         operand_left = operands.pop();         result = op

page80-栈用例-算术表达式求值

表达式由括号, 运算符和操作数(数字)组成.我们根据以下4中情况从左到右逐个将这些实体送入栈处理. (1)将操作数压入操作数栈: (2)将运算符压入运算符栈: (3)忽略左括号: (4)在遇到右括号时, 弹出一个运算符,弹出所需数量的操作符,并将运算符和操作符的运算结果压入操作数栈. [地杰斯特拉的双栈算术表达式求值算法] public class Evaluate { public static void main(String[] args) { Stack<String> ops = n

表达式求值:从“加减”到“带括号的加减乘除”的实践过程

本文乃Siliphen原创,转载请注明出处:http://blog.csdn.net/stevenkylelee ● 为什么想做一个表达式求值的程序 最近有一个需求,策划想设置游戏关卡的某些数值,这个数值不是一个常量,而是根据关卡的某些环境数据套上一个计算表达式算出来的.这个需求无法用excel拖表预计算出,因为关卡的环境数据只有在游戏中才能产生,在excel制表时,这些都是未知的.作为程序员,我可以把计算表达式硬编码在代码中,但这个做法有缺陷,如果策划要修改计算表达式的话,只能通过我修改程序并

【ThinkingInC++】1、三写表达式求值

/** * 功能:表达式求值 * 时间:2014年8月3日08:27:42 * 作者:cutter_point */ #include<iostream> #include<cstdlib> #include<sstream> #include<string> using namespace std; /******************************************************************************