C语言数据结构算法——简单表达式求值(支持计算小数及负数)

Posted Z.Q.Feng

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C语言数据结构算法——简单表达式求值(支持计算小数及负数)相关的知识,希望对你有一定的参考价值。


样例输入输出

输入为一段简单表达式(中缀),表达式中的数据可以是小数以及整数负数前后都有括号分隔,以下是一段输入样例:

4.5*(3.8-0.9*2)+2.5*(9.6/(-2.4))

输出为计算结果即 -1


中缀表达式转后缀表达式

代码如下,算法思路在注释里了,改进了算法加入了对小数以及负数的支持:

/*
以下为中缀表达式转后缀表达式:

while (从exp读取字符ch,ch!='\\0')

    ch为数字:
        将后续的所有数字均依次存放到postexp中,并以字符'#'标志数值串结束;
    ch为左括号'(':
        将此括号进栈到Optr中;
    ch为右括号')':
        将Optr中出栈时遇到的第一个左括号'('以前的运算符依次出栈并存放到postexp中,然后将左括号'('出栈;
    ch为'+'或'-':
        出栈运算符并存放到postexp中,直到栈空或者栈顶为'(',然后将'+'或'-'进栈;
    ch为'*'或'/':
        出栈运算符并存放到postexp中,直到栈空或者栈顶为'('、'+'或'-',然后将'+'或'-'进栈;


若exp扫描完毕,则将Optr中所有运算符依次出栈并存放到postexp中。

增添内容:

负数的判断:
    表达式首出现减号一定为负数,左括号后为减号该减号代表负数

小数点的处理:
    小数点直接进postexp,小数点前的数每次乘10,小数点后的数每次除以10
*/
void trans(char *exp, char postexp[])

    char e;
    SqStack *Optr;			//定义运算符栈指针
    InitStack(Optr);		//初始化运算符栈
    int i=0;				//i作为postexp的下标
    while (*exp != '\\0')	//exp表达式未扫描完时循环
    
        switch(*exp)
        
        case '(':           //判定为左括号
            exp++;	        //获取左括号后字符
            if (*exp == '-')//左括号后为减号则一定为负数
            
                postexp[i++] = *exp;    //减号进postexp
                exp++;
                while(*exp != ')')      //依次读取完负数的数值部分
                
                    postexp[i++] = *exp;
                    exp++;
                
                postexp[i++]='#';
                exp++;      //将负数对应的右括号处理掉(无需进栈)
                break;
            
            else
            
                Push(Optr,'('); //左括号进栈
                break;
            
        case ')':		   	//判定为右括号
            Pop(Optr,e);	//出栈元素e
            while (e!='(')	//不为'('时循环
            
                postexp[i++]=e;	//将e存放到postexp中
                Pop(Optr,e);	//继续出栈元素e
            
            exp++;		    //继续扫描其他字符
            break;
        case '+':			//判定为加号
            while (!StackEmpty(Optr))	//栈不空循环
            
                GetTop(Optr,e);		//取栈顶元素e
                if (e!='(')			//e不是'('
                
                    postexp[i++]=e;	//将e存放到postexp中
                    Pop(Optr,e);	//出栈元素e
                
                else				//e是'(时退出循环
                    break;
            
            Push(Optr,*exp);	//将'+'或'-'进栈
            exp++;				//继续扫描其他字符
            break;
        case '-':
            if (i == 0)         //减号出现在表达式首位一定为负数
            
                postexp[i++] = *exp;
                exp++;
                while(*exp != ')')
                
                    postexp[i++]=*exp;
                    exp++;
                
                postexp[i++]='#';
                exp++; // ')'
                break;
            
            else //以下内容同加号
            
                while (!StackEmpty(Optr))   //栈不空循环
                
                    GetTop(Optr,e);     //取栈顶元素e
                    if (e!='(')         //e不是'('
                    
                        postexp[i++]=e; //将e存放到postexp中
                        Pop(Optr,e);    //出栈元素e
                    
                    else             //e是'(时退出循环
                        break;
                
                Push(Optr,*exp);    //将'+'或'-'进栈
                exp++;              //继续扫描其他字符
                break;
            
        case '*':	//判定为'*'或'/'号
        case '/':
            while (!StackEmpty(Optr))   //栈不空循环
            
                GetTop(Optr,e);		//取栈顶元素e
                if (e=='*' || e=='/')
                
                    postexp[i++]=e;	//将e存放到postexp中
                    Pop(Optr,e);	//出栈元素e
                
                else	//e为非'*'或'/'运算符时退出循环
                    break;
            
            Push(Optr,*exp);    //将'*'或'/'进栈
            exp++;			   //继续扫描其他字符
            break;
        default:	//处理数字字符和点
            while ((*exp>='0' && *exp<='9') || *exp=='.') 	//判定为数字字符或点
            
                postexp[i++]=*exp;  //全部进postexp即可
                exp++;
            
            postexp[i++]='#';	  //用#标识一个数值串结束
        
    
    while (!StackEmpty(Optr))	  //此时exp扫描完毕,栈不空时循环
    
        Pop(Optr,e);	   //出栈元素e
        postexp[i++]=e;	  //将e存放到postexp中
    
    postexp[i]='\\0';	   //给postexp表达式添加结束标识
    DestroyStack(Optr);	  //销毁栈


后缀表达式求值

代码如下:

/*
后置表达式求值算法如下:

while (从postexp读取字符ch,ch!='\\0')

    ch为'+':
        从Opnd栈中出栈两个数值a和b,计算c=b+a;将c进栈;
    ch为'-':
        从Opnd栈中出栈两个数值a和b,计算c=b-a;将c进栈;
    ch为'*':
        从Opnd栈中出栈两个数值a和b,计算c=b*a;将c进栈;
    ch为'/':
        从Opnd栈中出栈两个数值a和b,若a不零,计算c=b/a;将c进栈;
    ch为数字字符:
        将连续的数字串转换成数值d,将d进栈;


返回Opnd栈的栈顶操作数即后缀表达式的值;

增添内容:
    利用flag增添对负数的处理以及对小数点的处理
*/
double compvalue(char *postexp)

    int flag = 1;
    double a, b, c, d, e, i;
    SqStack1 *Opnd;			//定义操作数栈
    InitStack1(Opnd);		//初始化操作数栈
    while (*postexp != '\\0')	//postexp字符串未扫描完时循环
    
        switch (*postexp)
        
            case '+':			//判定为'+'号
                Pop1(Opnd, a);	//出栈元素a
                Pop1(Opnd, b);	//出栈元素b
                c = b + a;		//计算c
                Push1(Opnd, c);	//将计算结果c进栈
                postexp++;
                break;
            case '-':			//判定为'-'号
                postexp++;      //获取减号后元素
                if (*postexp >= '0' && *postexp <= '9') //若减号后为数字则为负数
                
                    flag = -1;  //记flag为-1记录数值符号
                    break;
                
                else
                
                    Pop1(Opnd, a);	//出栈元素a
                    Pop1(Opnd, b);	//出栈元素b
                    c = b - a;		//计算c
                    Push1(Opnd, c);	//将计算结果c进栈
                    break;
                
            case '*':			//判定为'*'号
                Pop1(Opnd, a);	//出栈元素a
                Pop1(Opnd, b);	//出栈元素b
                c = b*a;		//计算c
                Push1(Opnd, c);	//将计算结果c进栈
                postexp++;
                break;
            case '/':			//判定为'/'号
                Pop1(Opnd, a);	//出栈元素a
                Pop1(Opnd, b);	//出栈元素b
                if (a != 0)
                
                    c = b / a;		//计算c
                    Push1(Opnd, c);	//将计算结果c进栈
                    postexp++;
                    break;
                
                else    //错误处理
                
                    printf("\\n\\t除零错误!\\n");
                    exit(0);	//异常退出
                
                postexp++;
                break;
            default:		//处理数字字符
                d = 0;		//转换成对应的数值存放到d中
                i = 1.0;    //处理小数用以每往后一位数除以10
                while ((*postexp >= '0' && *postexp <= '9') || *postexp == '.')
                
                    if (*postexp == '.')    //小数点后没往后一位数其值除以10
                    
                        i /= 10;
                        postexp++;
                        continue;
                    
                    if (i >= 1)     //小数点前的情况
                    
                        d = 10 * d + (*postexp - '0');
                        postexp++;
                    
                    else            //小数点后的情况
                    
                        d += i * (*postexp - '0');
                        postexp++;
                    
                
                Push1(Opnd, flag * d);	//将数值d进栈
                flag = 1;   //重新记符号为正号
                postexp++;
                break;
        
    
    GetTop1(Opnd, e);	//取栈顶元素e
    DestroyStack1(Opnd);//销毁栈
    return e;			//返回e


运行示例

编写主函数如下:

int main(int argc, char const *argv[])

    char exp[]="4.5*(3.8-0.9*2)+2.5*(9.6/(-2.4))";
    char postexp[MaxSize];
    trans(exp, postexp);
    cout << "中缀表达式 : " << exp << endl;
    cout << "后缀表达式 : " << postexp << endl;
    cout << "表达式的值 : " << compvalue(postexp) << endl;
	return 0;

运行结果如下:


想要完整代码(就是顺序栈部分你们也可以自行百度)可下载我上传的资源:C语言数据结构算法-简单表达式求值(支持计算负数及小数)

主要重要的部分已经在这啦~

以上是关于C语言数据结构算法——简单表达式求值(支持计算小数及负数)的主要内容,如果未能解决你的问题,请参考以下文章

C语言编一个实现简单的算术表达式求值的代码。

C语言 任意表达式求值。(栈的应用

判断C语言算术表达式的合法性

C语言:计算表达式x^y的值,分别输出它们的整数部分和小数部分。

C++:算术表达式求值

数据结构算法C语言实现--- 3.2栈的应用举例:迷宫求解与表达式求值