堆栈实现计算数学表达式

直接用两个栈计算方法子程序流程图
在这里插入图片描述

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<math.h>

#include<stdbool.h>

#define MAXSIZE 100
#define FIGUREMAXSIZE 20

int level(char op);
double calcValue(double od1, double od2, char tempop);
bool isOp(char ch);


//方法一:用两个栈直接计算
double calcDirect(char str[])
{
    struct             //用结构体创建操作符栈
    {
        char data[MAXSIZE];//用来存放操作符
        int top;
    } op;
    struct          //用结构体创建值栈
    {
        double data[MAXSIZE];//用来存放操作数
        int top;
    } od;

    op.top = -1;//初始化操作符栈,令下标为-1
    od.top = -1;//初始化值栈

    char ch;
    char tempStr[FIGUREMAXSIZE];//存储临时数组存储子串
    double tempData;//存储将子串转化成double类型的数
    double od1, od2; //存储值栈依次pop出来的操作数
    char tempop;//存储操作符

    int length = strlen(str);//计算str数组的长度
    int i = 0;//声明字符数组循环索引
    int j = 0;//声明数值子串索引

    while(i < length)
    {
        ch = str[i];

        if((ch >= '0' && ch <= '9') || ch == '.') //若为数值或小数点
        {
            j = 0;
            memset(tempStr, 0, FIGUREMAXSIZE);
            tempData = 0;
            while((ch >= '0' && ch <= '9') || ch == '.') //截取子串
            {
                tempStr[j++] = ch;//赋值给临时数组
                ch = str[++i];
            }
            tempStr[j] = '\0';
            tempData = atof(tempStr);//将子串转化成double类型的数
            od.data[++od.top] = tempData; //入值栈
        }
        else if(isOp(ch))//若为操作符
        {
            if(op.top == -1) //如果栈为空,直接进栈
            {
                op.data[++op.top] = ch; //进栈操作
            }
            else if(ch == '(') //如果为(,直接进栈
            {
                op.data[++op.top] = ch; //进栈操作
            }
            else if(ch == ')') //如果为),一直出栈直到遇到(
            {
                while(level(op.data[op.top]) != -1) //若栈顶元素不为(,进入while循环
                {
                    od2 = od.data[od.top--];
                    od1 = od.data[od.top];
                    tempop = op.data[op.top--];
                    od.data[od.top] = calcValue(od1, od2, tempop); //计算出结果后入值栈
                    if(op.top == -1)break; //如果操作符栈为空,跳出循环
                }
                op.top--;//左括号pop出来
            }
            //如果所扫描的操作符优先等级比栈顶元素高,直接进栈
            else if(level(ch) > level(op.data[op.top]))
            {
                op.data[++op.top] = ch; //进栈操作
            }
            else
            {
                //如果所扫描的操作符优先等级没有栈顶元素高,
                //一直出栈直到比栈顶元素优先级高
                while(level(ch) <= level(op.data[op.top]))
                {
                    od2 = od.data[od.top--];
                    od1 = od.data[od.top];
                    tempop = op.data[op.top--];
                    od.data[od.top] = calcValue(od1, od2, tempop); //计算出结果后入值栈
                    if(op.top == -1)break; //如果操作符栈为空,跳出循环
                }
                op.data[++op.top] = ch; //比栈顶元素优先级高,入操作符栈
            }
            i++;//str下标加1,向后扫描
        }
        else//输入有误
        {
            printf("输入的表达式有误\n");

            return 0;
        }
    }

    while(op.top != -1) //扫描结束后如果操作符栈不为空,出栈直至为空
    {
        od2 = od.data[od.top--];
        od1 = od.data[od.top];
        tempop = op.data[op.top--];
        od.data[od.top] = calcValue(od1, od2, tempop); //计算结果后入值栈
    }

    return od.data[od.top];//将结束后值栈中的数pop出来,即为计算结果
}


//函数实现中缀转后缀,将存储数学表达式的数组str传参进来,exp存储后缀表达式
void transfer(char str[], char exp[])
{
    struct
    {
        char data[MAXSIZE];//用来存放操作符
        int top;//数组下标
    } op; //用结构体创建操作符栈
    op.top = -1; //给操作符栈初始化,令下标为-1

    char ch;
    int i = 0, j = 0, tempi = 0;
    while(ch != '\0')
    {
        ch = str[i]; //取str数组的第i个元素赋值给ch
        if((ch >= '0' && ch <= '9') || ch == '.') //对数值操作
        {
            tempi = i; //若ch为数字或小数点,将其下标值赋给临时下标tempi
            //依次向后扫描str数组,若一直为数字,跳入while循环
            while((ch >= '0' && ch <= '9') || ch == '.')
            {
                tempi++;
                exp[j] = ch; //将数字存入exp数组中
                j++;
                ch = str[tempi]; //取str数组中下标为tempi的元素赋给ch
            }
            exp[j] = '#';
            j++;//用#做分隔符,将数值分隔开
            i = tempi; //跳出循环,将此时的tempi赋给i,继续向后扫描
        }
        //对操作符操作
        else if(isOp(ch))
        {
            if(ch == '(') //如果为(,直接进栈
            {
                op.top++;
                op.data[op.top] = ch; //进栈操作
            }
            else if(ch == ')')
            {
                //如果为),一直出栈直到遇到(
                while(level(op.data[op.top]) != -1) //若栈顶元素不为(,进入while循环
                {
                    exp[j] = op.data[op.top]; //操作符出栈,存入exp数组中
                    op.top--;
                    j++;
                    if(op.top == -1)break; //如果栈为空,跳出循环
                }
                op.top--;//左括号pop出来
            }
            else if(op.top == -1) //如果栈为空,直接进栈
            {
                op.top++;
                op.data[op.top] = ch; //进栈操作
            }
            //如果所扫描的操作符优先等级比栈顶元素高,直接进栈
            else if(level(ch) > level(op.data[op.top]))
            {
                op.top++;
                op.data[op.top] = ch; //进栈操作
            }
            else
            {
                //如果所扫描的操作符优先等级没有栈顶元素高,
                //一直出栈直到比栈顶元素优先级高
                while(level(ch) <= level(op.data[op.top]))
                {
                    exp[j] = op.data[op.top]; //出栈存入exp数组中
                    op.top--;
                    j++;
                    if(op.top == -1)break; //如果栈为空,跳出循环
                }
                op.top++;
                op.data[op.top] = ch; //比栈顶元素优先级高,入栈
            }
            i++;//str下标加1,向后扫描
        }
        else//输入有误
        {
            printf("输入的表达式有误\n");

            return;
        }
    }
    while(op.top != -1) //扫描结束后如果操作符栈不为空,出栈直至为空
    {
        exp[j] = op.data[op.top]; //出栈存入exp数组中
        op.top--;
        j++;
    }
    exp[j] = '\0'; //赋\0结束exp字符数组
}

//方法二:先将中缀表达式转换成后缀表达式,再进行计算
double calcTransfer(char exp[])
{
    struct  //用结构体创建值栈
    {
        double data[MAXSIZE]; //存储数值
        int top;
    } od;
    double d;  //声明d变量存储数值
    double od1, od2; //存储值栈依次pop出来的操作数
    char ch;
    char tempch[20]; //声明临时数组存储子串
    int j = 0, t;
    int length = strlen(exp); //计算exp数组的长度
    od.top = -1; //初始化值栈,令下标为-1
    while(j < length)
    {
        ch = exp[j]; //提取exp中第j个元素
        if(!isOp(ch))
        {
            //如果为数字或小数点
            d = 0;
            t = 0;
            while((ch >= '0' && ch <= '9') || ch == '.')
            {
                tempch[t] = ch;
                t++;//依次存放到临时数组中
                j++;
                ch = exp[j];
            }
            tempch[t] = '\0'; //结束tempch数组
            d = atof(tempch); //将子串转化成double类型的数
            od.top++;
            od.data[od.top] = d; //入值栈
        }
        else                   //若为操作符,从值栈中pop出两个数计算
        {
            od2 = od.data[od.top];
            od.top--;//先出栈的赋给od2
            od1 = od.data[od.top];       //后出栈的赋给od1
            od.data[od.top] = calcValue(od1, od2, ch); //计算出结果后再入栈
        }
        j++;
    }
    return od.data[od.top];//将结束后值栈中的数pop出来,即为计算结果
}

bool isOp(char ch)
{
    if(ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '%' || ch == '(' || ch == ')' || ch == '^')
        return true;
    return false;
}

int level(char op)//判断操作符优先等级
{
    if(op == '+' || op == '-')//若为+、-,等级为1
        return 1;
    else if(op == '*' || op == '/' || op == '%')
        return 2;         //若为*、/、%,等级为2
    else if(op == '^')
        return 3;         //若为^,等级为3
    else if(op == '(')
        return -1 ;      //若为(,等级为-1
    else
        return -3;       //其他等级为-3;
}

double calcValue(double od1, double od2, char tempop) //计算
{
    switch(tempop) {
    case '+':
        return od1 + od2;//计算加法
    case '-':
        return od1 - od2;//计算减法
    case '*':
        return od1 * od2;//计算乘法
    case '/':
        return od1 / od2;//计算除法
    case '%':
        return fmod(od1, od2); //求余
    case '^':
        return pow(od1, od2);//指数
    }
    return 0;
}

int main()
{
    char str[MAXSIZE], exp[MAXSIZE];//定义str数组存放数学表达式
    printf("输入算术表达式:\n");
    gets(str);       //从控制台输入算数表达式
    printf("表达式为:%s\n", str);

    printf("直接计算结果为:%lf\n", calcDirect(str));

    transfer(str, exp);
    printf("后缀表达式为:%s\n", exp);
    printf("后缀转换计算结果为:%lf\n", calcTransfer(exp));

    return  0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值