• 表达式求值算法、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    /*              +      -      *      /      ^      !      (      )       */
     23    /* --  + */    '>',   '>',   '<',   '<',   '<',   '<',   '<',   '>',   '>',
     24    /* |   - */    '>',   '>',   '<',   '<',   '<',   '<',   '<',   '>',   '>',
     25    /* 栈  * */    '>',   '>',   '>',   '>',   '<',   '<',   '<',   '>',   '>',
     26    /* 顶  / */    '>',   '>',   '>',   '>',   '<',   '<',   '<',   '>',   '>',
     27    /* 运  ^ */    '>',   '>',   '>',   '>',   '>',   '<',   '<',   '>',   '>',
     28    /* 算  ! */    '>',   '>',   '>',   '>',   '>',   '>',   ' ',   '>',   '>',
     29    /* 符  ( */    '<',   '<',   '<',   '<',   '<',   '<',   '<',   '=',   ' ',
     30    /* |   ) */    ' ',   ' ',   ' ',   ' ',   ' ',   ' ',   ' ',   ' ',   ' ',
     31    /* --  */    '<',   '<',   '<',   '<',   '<',   '<',   '<',   ' ',   '='
     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 '': 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 ( '' == *q ) { *p = ''; 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当前长度(以''结尾,长度n + 1)
     78    char buf[64];
     79    if ( opnd != ( float ) ( int ) opnd ) sprintf ( buf, "%.2f ", opnd ); //浮点格式,或
     80    else                          sprintf ( buf, "%d ", ( 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当前长度(以''结尾,长度n + 1)
     86    rpn = ( char* ) realloc ( rpn, sizeof ( char ) * ( n + 3 ) ); //扩展空间
     87    sprintf ( rpn + n, "%c ", optr ); rpn[n + 2] = ''; //接入指定的运算符
     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:
    ");
    109    while(!opndStk.empty()){
    110       printf("%.3f ",opndStk.top());
    111       opndStk.pop();
    112    }
    113 }
    114 void print(stack<char> optrStk){
    115    printf("optrStk:
    ");
    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 ( "
    expr:" );
    124    for ( char* p = expr; '' != *p; p++ ) printf ( " %c", *p ); printf ( " $
    expr:" );
    125    for ( char* p = expr; p < pCh; p++ ) printf ( "  " );
    126    if ( '' != * ( pCh - 1 ) )
    127       { for ( char* p = pCh; '' != *p; p++ ) printf ( " %c", *p ); printf ( " $" ); }
    128    printf ( "
    expr:" );
    129    for ( char* p = expr; p < pCh; p++ ) printf ( "--" ); printf ( " ^
    
    " );
    130    print ( optrStk ); printf ( "
    " );
    131    print ( opndStk ); printf ( "
    " );
    132    printf ( "RPN:
     %s
    
    ", 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 ( '' ); //尾哨兵''也作为头哨兵首先入栈
    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 '=': //优先级相等(当前运算符为右括号或者尾部哨兵'')时
    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("||====================================================||
    ");
    173    printf("||******************表达式求值************************||
    ");
    174    printf("||***支持加、减、乘、除、乘方、阶乘、左括号、右括号***||
    ");
    175    printf("||====================================================||
    ");
    176 
    177    printf ( "
    please scanf the number of evaluate:
    " );
    178    scanf("%d",&n);
    179    getchar();//处理第一行末的'
    '
    180    while(n--)
    181    {
    182       char str[100];
    183       system ( "cls" );
    184       printf ( "
    please scanf the evaluate:
    " );
    185       gets(str);//表达式求值(入口)
    186       printf ( "
    Press [Enter] key to evaluate: [%s]
    ", str );getchar();
    187       char* rpn = ( char* ) malloc ( sizeof ( char ) * 1 );   rpn[0] = ''; //逆波兰表达式
    188       float value = evaluate ( removeSpace ( str ), rpn ); //求值
    189       printf ( "EXPR	: %s
    ", str ); //输出原表达式
    190       printf ( "RPN	: [ %s]
    ", rpn ); //输出RPN
    191       printf ( "Value	= %.3f = %d
    ", 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    /*              +      -      *      /      ^      !      (      )       */
     18    /* --  + */    '>',   '>',   '<',   '<',   '<',   '<',   '<',   '>',   '>',
     19    /* |   - */    '>',   '>',   '<',   '<',   '<',   '<',   '<',   '>',   '>',
     20    /* 栈  * */    '>',   '>',   '>',   '>',   '<',   '<',   '<',   '>',   '>',
     21    /* 顶  / */    '>',   '>',   '>',   '>',   '<',   '<',   '<',   '>',   '>',
     22    /* 运  ^ */    '>',   '>',   '>',   '>',   '>',   '<',   '<',   '>',   '>',
     23    /* 算  ! */    '>',   '>',   '>',   '>',   '>',   '>',   ' ',   '>',   '>',
     24    /* 符  ( */    '<',   '<',   '<',   '<',   '<',   '<',   '<',   '=',   ' ',
     25    /* |   ) */    ' ',   ' ',   ' ',   ' ',   ' ',   ' ',   ' ',   ' ',   ' ',
     26    /* --  */    '<',   '<',   '<',   '<',   '<',   '<',   '<',   ' ',   '='
     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当前长度(以''结尾,长度n + 1)
     45    char buf[64];
     46    if ( opnd != ( float ) ( int ) opnd ) sprintf ( buf, "%.2f ", opnd ); //浮点格式,或
     47    else                          sprintf ( buf, "%d", ( 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当前长度(以''结尾,长度n + 1)
     54    rpn = ( char* ) realloc ( rpn, sizeof ( char ) * ( n + 3 ) ); //扩展空间
     55    sprintf ( rpn + n, "%c", optr ); rpn[n + 2] = ''; //接入指定的运算符
     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 '': 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 ( '' ); //尾哨兵''也作为头哨兵首先入栈
    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 '=': //优先级相等(当前运算符为右括号或者尾部哨兵'')时
    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 ( '' == *q ) { *p = ''; 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 ( "
    Press any key to evaluate: [%s]
    ", str );
    148       char* rpn = ( char* ) malloc ( sizeof ( char ) * 1 );   rpn[0] = ''; //逆波兰表达式
    149       float value = evaluate ( removeSpace ( str ), rpn ); //求值
    150       ///*DSA*/printf ( "EXPR	: %s
    ", str ); //输出原表达式
    151       ///*DSA*/printf ( "%s
    ", rpn ); //输出RPN
    152       /*DSA*/printf ( "%d
    ",( int ) value ); //输出表达式的值
    153       free ( rpn );   rpn = NULL;
    154    }
    155    return 0;
    156 }
    View Code

    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    /*              +      -      *      /      ^      !      (      )       */
     18    /* --  + */    '>',   '>',   '<',   '<',   '<',   '<',   '<',   '>',   '>',
     19    /* |   - */    '>',   '>',   '<',   '<',   '<',   '<',   '<',   '>',   '>',
     20    /* 栈  * */    '>',   '>',   '>',   '>',   '<',   '<',   '<',   '>',   '>',
     21    /* 顶  / */    '>',   '>',   '>',   '>',   '<',   '<',   '<',   '>',   '>',
     22    /* 运  ^ */    '>',   '>',   '>',   '>',   '>',   '<',   '<',   '>',   '>',
     23    /* 算  ! */    '>',   '>',   '>',   '>',   '>',   '>',   ' ',   '>',   '>',
     24    /* 符  ( */    '<',   '<',   '<',   '<',   '<',   '<',   '<',   '=',   ' ',
     25    /* |   ) */    ' ',   ' ',   ' ',   ' ',   ' ',   ' ',   ' ',   ' ',   ' ',
     26    /* --  */    '<',   '<',   '<',   '<',   '<',   '<',   '<',   ' ',   '='
     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当前长度(以''结尾,长度n + 1)
     45    char buf[64];
     46    if ( opnd != ( float ) ( int ) opnd ) sprintf ( buf, "%.2f", opnd ); //浮点格式,或
     47    else                          sprintf ( buf, "%d", ( 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当前长度(以''结尾,长度n + 1)
     53    rpn = ( char* ) realloc ( rpn, sizeof ( char ) * ( n + 3 ) ); //扩展空间
     54    sprintf ( rpn + n, "%c", optr ); rpn[n + 2] = ''; //接入指定的运算符
     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 '': 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 ( '' ); //尾哨兵''也作为头哨兵首先入栈
     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 '=': //优先级相等(当前运算符为右括号或者尾部哨兵'')时
    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 ( '' == *q ) { *p = ''; 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 ( "
    Press any key to evaluate: [%s]
    ", str );
    148       char* rpn = ( char* ) malloc ( sizeof ( char ) * 1 );   rpn[0] = ''; //逆波兰表达式
    149       float value = evaluate ( removeSpace ( str ), rpn ); //求值
    150       ///*DSA*/printf ( "EXPR	: %s
    ", str ); //输出原表达式
    151       /*DSA*/printf ( "%s
    ", rpn ); //输出RPN
    152       ///*DSA*/printf ( "Value	= %.1f = %d
    ", value, ( int ) value ); //输出表达式的值
    153       free ( rpn );   rpn = NULL;
    154    }
    155    return 0;
    156 }
    View Code

    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    /*              +      -      *      /      ^      !      (      )       */
     17    /* --  + */    '>',   '>',   '<',   '<',   '<',   '<',   '<',   '>',   '>',
     18    /* |   - */    '>',   '>',   '<',   '<',   '<',   '<',   '<',   '>',   '>',
     19    /* 栈  * */    '>',   '>',   '>',   '>',   '<',   '<',   '<',   '>',   '>',
     20    /* 顶  / */    '>',   '>',   '>',   '>',   '<',   '<',   '<',   '>',   '>',
     21    /* 运  ^ */    '>',   '>',   '>',   '>',   '>',   '<',   '<',   '>',   '>',
     22    /* 算  ! */    '>',   '>',   '>',   '>',   '>',   '>',   ' ',   '>',   '>',
     23    /* 符  ( */    '<',   '<',   '<',   '<',   '<',   '<',   '<',   '=',   ' ',
     24    /* |   ) */    ' ',   ' ',   ' ',   ' ',   ' ',   ' ',   ' ',   ' ',   ' ',
     25    /* --  */    '<',   '<',   '<',   '<',   '<',   '<',   '<',   ' ',   '='
     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当前长度(以''结尾,长度n + 1)
     44    char buf[64];
     45    if ( opnd != ( float ) ( int ) opnd ) sprintf ( buf, "%.2f ", opnd ); //浮点格式,或
     46    else                          sprintf ( buf, "%d", ( 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当前长度(以''结尾,长度n + 1)
     52    rpn = ( char* ) realloc ( rpn, sizeof ( char ) * ( n + 3 ) ); //扩展空间
     53    sprintf ( rpn + n, "%c", optr ); rpn[n + 2] = ''; //接入指定的运算符
     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 '': 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 ( '' ); //尾哨兵''也作为头哨兵首先入栈
     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 '=': //优先级相等(当前运算符为右括号或者尾部哨兵'')时
    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 ( '' == *q ) { *p = ''; 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]='';
    148    //for ( int i = 0; i < strlen(str); i++ ) { //逐一处理各命令行参数(表达式)
    149       ///*DSA*/system ( "cls" ); //
    150    //printf ( "
    Press any key to evaluate: [%s]
    ", str );
    151       char* rpn = ( char* ) malloc ( sizeof ( char ) * 1 );   rpn[0] = ''; //逆波兰表达式
    152       float value = evaluate ( removeSpace ( str ), rpn ); //求值
    153       ///*DSA*/printf ( "EXPR	: %s
    ", str ); //输出原表达式
    154       ///*DSA*/printf ( "%s
    ", rpn ); //输出RPN
    155       /*DSA*/printf ( "%.2f
    ",value ); //输出表达式的值
    156       free ( rpn );   rpn = NULL;
    157    }
    158    return 0;
    159 }
    View Code

    附: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
    ",Evaluate());
    30     return 0;
    31 }
    View Code
  • 相关阅读:
    Fiddler常用命令
    在Fiddler中添加自己所需的显示列
    清除微信小程序的缓存
    关于接口幂等性的一些总结
    外边距塌陷如何解决?
    CSS背景属性
    CSS链接伪类:超链接的状态
    CSS三大特性
    CSS块元素、行内元素、行内块元素的转换
    CSS行内块元素(内联元素)
  • 原文地址:https://www.cnblogs.com/swanGooseMan/p/4262351.html
Copyright © 2020-2023  润新知