码迷,mamicode.com
首页 > 其他好文 > 详细

表达式求解程序(CPP实现)

时间:2014-06-30 10:41:00      阅读:162      评论:0      收藏:0      [点我收藏+]

标签:blog   get   2014   os   cti      

 

/**
*    This is a program for solve mathematical expression. Just like:
*            "1+4*3/2+22*(3+2*(3-4))"
*
*    To solve this problem, Let us see it by a view of priority. The rules as following:
*        1). the priority of plus sign is 1, and minus sign too.
*        2). the priority of product sign and sign of division is 2.
*        3). the priority of bracket is 3.
*
*    so, we can convert the expression above to:
*
*
*                                                                                 [1]
*                                                                                  .
*                                                                            -------------
*                                                                     [2]   .              .
*                                                           [1]        .    .              .
*                                                             .         .    .              .  
*                                                        --------------------------------
*                        [2]    [2]             [2]   .                                      .
*                [1]      .       .     [1]       .    .                                      .
*                 .        .       .      .         .    .                                      .
*           " 1  +  4  *  3  /  2  +  22  *    (  3  +  2  *   (  3  -  4   )   )  "
*
*    It is easy to know, we can‘t compute a sign in rising edge. And on the other way, we could dispose those brackets by a special way. that‘s means we could get a more

*    simple expression without bracket
*
*               [1]   [2]    [2]    [1]      [2]            [4]    [5]       [7]
*          " 1  +  4  *  3  /  2  +  22  *          3  +  2  *      3  -  4"
*
*    and then what we should to do is just as follow:
*
*        step 1: get a operator .
*        step 2: compare the priority with it‘s last one‘s.
*                    --   ‘>=‘ , compute it.
*                    --   ‘<‘ , return to the step above.
*
*    if arrvied the end , we will get a new expression. The priority of totally expression is increase by degree.
*
*                 [1]    [1]     [2]    [4]   [5]    [7]
*            " 1  +  6  +  22  *  3  +  2  *  3  - 4  "
*
*    In the last, what we need is compute all operator by inverted order.
*
*/

 

#include <iostream>
#include <stdio.h>
#include "../stack.h"

#define NUMS_DEP	20
#define SYMS_DEP	20

/**
*    All input symbol must be one of the types. we will deal those symbol
*    with a corresponding operation. Need to say, number is also belong to
*    symbol.
*/
enum SYMBOL {
        S_NUM,
        S_PLUS,
        S_SUB,
        S_MUL,            //multiply
        S_DIV,            //division
        S_BRAL,        //left bracket
        S_BRAR,        //right bracket
        S_INVAID,
        S_END,            // the end of expression
        S_MAX,
};

/**
*    All symbols have a priority for operation.
*/
enum SYM_PRI {
        PR_NUM = 0,
        PR_INVALID = 0,
        PR_PLUS = 1,
        PR_SUB = 1,
        PR_MUL = 2,
        PR_DIV = 2,
        PR_MAX,
};

/**
*    record information about symbol.  
*/
struct OperatorS {
        //what's type?
        SYMBOL    sym;
        //priority
        int            prior;
        //used to record the value of number.
        int            val;
};

class Calculater {
        public:
                Calculater( );
                ~Calculater( );
                //initialize the environment
                bool set( char *expr);
                //solve 
                bool work( void);
                //show the result
                void show( void);

        private:
                //deal with symbol
                bool dwItem( OperatorS &item);
                //get a symbol from the expression string
                bool getItem( OperatorS &item);

                //deal with bracket, 
                bool adjustPri( OperatorS &item);
                //modify the priority of a symbol
                bool calcuPri( OperatorS &item);
                //calculate the value of a symbol with its' corresponding values.
                bool calcuSym( OperatorS &sym);
                //convert a string to a interger
                bool str2Inter( char *begin, int &val, int &len);
                /*
            * when deal with a symbol, we found it have a feature, first-in last-out.
            * that is same as the feature of the stack.
            */
                //stack for save symbol
                STACK<OperatorS>	sym_s;
                //stack for save number
                STACK<int>			num_s;
                //mathematical expression
                char *    expr;
                //current position
                int        cur_ind;
                /*
            * current priority. if encounter a bracket, this value will change for 
            * revise the priority of symbol after it.
            */
                int        cur_pri;
                // the result will be restore in here.
                int        sum;
};


Calculater::Calculater( ):num_s(NUMS_DEP),sym_s(SYMS_DEP)
{

        this->expr = NULL;
        this->cur_ind = 0;
        this->cur_pri = 0;
        this->sum = 0;
}

Calculater::~Calculater( )
{}

bool Calculater::set(char * expr)
{
        this->expr = expr;
        this->cur_ind = 0;
        this->cur_pri = 0;
        this->sum = 0;

        return true;
}


/**
*	core function, work for solve the mathematical expression.
*/
bool Calculater::work( void)
{

        OperatorS	item;
/*
*    untill all of symbols be computed.
*/
        while( ('\0'!=this->expr[this->cur_ind])
                        ||(this->num_s.getEleNum( )!=1) )
        {
                //get a symbol
                        //Y: continue
                        //N: remain the last symbol
                if( !this->getItem( item) )
                        return false;

                //deal with symbol
                this->dwItem( item);
        }

        this->num_s.pop( this->sum);
        return true;
}

/**
*    get a item from the string, and build a symbol.
*/
bool Calculater::getItem( OperatorS & item)
{
        char        firstc = this->expr[this->cur_ind];
        this->cur_ind ++;

        OperatorS    tmp;
        switch( firstc)
        {
                case '+':
                        tmp.sym = S_PLUS;
                        tmp.prior = PR_PLUS;
                        tmp.val = 0;
                        break;
                case '-':
                        tmp.sym = S_SUB;
                        tmp.prior = PR_SUB;			
                        tmp.val = 0;
                        break;
                case '*':
                        tmp.sym = S_MUL;
                        tmp.prior = PR_MUL;
                        tmp.val = 0;
                        break;
                case '/':
                        tmp.sym = S_DIV;
                        tmp.prior = PR_DIV;
                        tmp.val = 0;
                        break;
                case '(':
                        tmp.sym = S_BRAL;
                        tmp.prior = PR_MAX;
                        tmp.val = 0;
                        break;
                case ')':
                        tmp.sym = S_BRAR;
                        tmp.prior = PR_MAX;
                        tmp.val = 0;
                        break;
                case '0'...'9':
                {
                        int    len = 0;
                        tmp.sym = S_NUM;
                        tmp.prior = PR_INVALID;
                        this->str2Inter( this->expr + this->cur_ind - 1, tmp.val, len);
                        this->cur_ind += len-1;
                        break;
                }
                /*
            *    when arrived the end, create a end sign.
            */
                case '\0':
                {
                        tmp.sym = S_END;
                        tmp.prior = PR_INVALID;
                        tmp.val = 0;
                        break;
                }
                default :
                        return false;
                        break;
        }

        item = tmp;
        return true;
}

/**
*    get a number from the string. if success, the value will
*    be store in @val, and the length of reading will be store
*    in @len.
*/
bool Calculater::str2Inter(char * begin,int & val,int & len)
{
        int    tmp_val = 0;
        int    tmp_len = 0;

        while( (begin[tmp_len]>='0')
                        &&(begin[tmp_len]<='9'))
        {
                tmp_val = tmp_val*10 + begin[tmp_len] - '0';
                tmp_len++;
        }

        val = tmp_val ;
        len = tmp_len ;
        return true;
}

//deal with symbol
bool Calculater::dwItem( OperatorS & item)
{
        printf("sym: %x,	prior: %x,	val: %d\n", item.sym, item.prior, item.val);

        switch( item.sym)
        {
                //case 1: symbol is a number.
                        //push in @num_s.
                case S_NUM :
                        this->num_s.push( item.val);
                        break;
                //case 2: symbol is a operator.
                case S_END:
                case S_PLUS...S_DIV :
                {
                        //compute priority,  cur + = ()
                        this->calcuPri( item);
                        //compare with the last operator.
                                    // <= , compute the last operator with the last two numbers.
                                    //do the compare above untill the new operator greater than the last one.
                                    // > , do nothing.
                                    // * , push the new operator in @sym_s.
                        //printf("sym: %x,	prior: %x,	val: %d\n", item.sym, item.prior, item.val);
                        OperatorS    last;
                        do{
                                    if(!this->sym_s.pop( last))
                                            break;    //there is no symbol 
                                    if( item.prior<=last.prior)
                                    {
                                            this->calcuSym( last);
                                            continue;
                                    }
                                    this->sym_s.push( last);
                            }
                            while( item.prior <= last.prior);

                            this->sym_s.push( item);
                            break;
                }
                //deal with bracket 
                case S_BRAL...S_BRAR:
                {
                        this->adjustPri( item);
                        break;
                }
                default :
                        return false;
        }

        return true;
}

bool Calculater::adjustPri(OperatorS & item)
{
        switch( item.sym)
        {
                case S_BRAL:
                        this->cur_pri += item.prior;
                        break;
                case S_BRAR:
                        this->cur_pri -= item.prior;
                        break;
                default :
                        return false;
                        break;
        }

        return true;
}

/**
*    compute the priority of this symbol.
*/
bool Calculater::calcuPri( OperatorS & item)
{

        switch( item.sym)
        {
                case S_END:
                        break;
                default :
                        item.prior += this->cur_pri;
                        break;
        }
	
        return true;
}

bool Calculater::calcuSym(OperatorS & sym)
{
        int    val1, val2, sum;
        this->num_s.pop( val1);
        this->num_s.pop( val2);
        sum = 0;

        switch( sym.sym)
        {
                case S_PLUS:
                        sum = val2 + val1;
                        break;
                case S_SUB:
                        sum = val2 - val1;
                        break;
                case S_MUL:
                        sum = val2 * val1;
                        break;
                case S_DIV:
                        sum = val2/val1;;
                        break;
                default :
                        return false;
                        break;
        }

        this->num_s.push( sum);

        return true;
}


void Calculater::show(void)
{
        printf(" %s = %d\n", this->expr, this->sum);
}


#define EXPR        "1+24*3/12-4*(5+6-7*2*(2+3*4))*22"

int main()
{
        Calculater	    cal;
        cal.set( EXPR);
        cal.work( );
        cal.show( );

        return 0;
}


 

 

 

 

 

 

表达式求解程序(CPP实现),布布扣,bubuko.com

表达式求解程序(CPP实现)

标签:blog   get   2014   os   cti      

原文地址:http://blog.csdn.net/u012301943/article/details/35559155

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!