数据结构(二)——栈和队列之表达式求解

题目描述:给定一个表达式,先求其后缀式,然后根据后缀式求表达式的值(测试用例 中,操作数的个数大于5)。

本题可以运用数据结构中的栈进行求解,其中有三个比较关键的步骤

一、如何将输入的字符数据中的两位即两位以上的数据转化成int型进行计算。
二、如何将表达式转化成逆波兰符号式并计算

这里,我先给出我的栈的结构体定义

typedef struct stack
{
    char sign[MAX][2];//存储数据的数组,一列为数据域,一列为符号域。
    //符号域中,0表示该数据域存储的为数字,1表示为'-'或'+',2表示为'*'或'/',3表示为'(',4表示为')',-1'#'
    int num[MAX];
    int size;//栈顶指针
}stack,*pstack;//定义栈的结构体

在稍后的处理中,我会用到两个栈,一个用来存储数据,一个用来存储运算符。

一、如何将输入的字符数据中的两位及两位以上的数据转化成int型进行计算。
1.首先我们要做的是将操作数和计算符分别识别,若是计算符,我们便将其存入存储运算符的栈中;若不是计算符,我们则将其进行转化为int型,并扫描下一个数据。
2.若下一个数据依旧是操作数,则将上一个操作数e1 * 10,并加上这个操作数,得到一个int型的参数,再继续扫描下一个数据。
3.直到下一个数据为计算符时,将int型参数e1存入操作数栈中。
在一边执行存入数据操作同时,也一边对数据进行着计算。放上代码

void renewdata_and_calculate(pstack stnum,pstack stsign,char b[MAX])
{
    int j,k=0;
    int e1=0;
    stsign->sign[stsign->size][0]='#';
    stsign->size++;
    for(j=0;b[j]!='#';j++)//判断b数组是否遍历完整
    {
        while(b[j]!='+'&&b[j]!='-'&&b[j]!='*'&&b[j]!='/'&&b[j]!='('&&b[j]!=')'&&b[j]!='#')//排除b[j]是运算符的可能
        {
            if((b[j]-'0')==0)//判断b[j]是否是0这个特殊数
            {
                e1=e1*10+b[j]-'0';//计算e1
                k++;//标记e1为特殊数0
            }
            else
            {
                e1=e1*10+b[j]-'0';//当e1不为0时,计算e1的数据
            }
            j++;//推动b数组遍历
        }
        if(e1!=0||k!=0)//判断是否是数字
        {
            Pushnum(stnum,e1);//存储数字
            printf("%d ",e1);
            if(b[j]!='#')
            {
                Pushsign(stsign,b[j]);//存储运算符
                Calculate(stnum,stsign);
            }
            else
            {
                Pushsign(stsign,b[j]);//存储运算符
                Calculate(stnum,stsign);
                j--;
            }
            k=0;//重新初始化标记数
            e1=0;//重新初始化计算的数据
        }
        else
        {
            Pushsign(stsign,b[j]);//存储运算符
            Calculate(stnum,stsign);
        }
    }
}

二、如何将表达式转化成逆波兰符号式
在存储计算符的时候,我们要考虑如何让计算机按照加减乘除的计算法进行计算。这里,我是运用了赋予计算符优先级,结合栈的数据结构进行操作
1.设立两个栈,一个用来存储操作数,一个用来存储计算符
2.给每个会出现的计算符赋优先级。符号域中,0表示该数据域存储的为数字,1表示为’-‘或’+’,2表示为’*‘或’/’,3表示为’(’,4表示为’)’,-1’#’。
3.当栈中数据,若将要进入栈中的运算符的优先级大于栈顶元素,则将计算符入栈(个别特俗运算符除外,如‘)’和‘#’);否则,则将栈顶元素出栈,并依次取出存储操作数栈的栈顶元素两个,进行计算,得到的操作数存入存储操作数的栈中。直到读到‘#’符号,则将两个栈中的元素全部依次进行运算,以一个计算符,对应两个操作数的方式,进行运算,直到只剩一个操作数,并输出结果。

void Calculate(pstack stnum,pstack stsign)
{
    int n1;
    int i,j;
    char e1,e2;//用于暂时的存储数据
    if(stsign->sign[stsign->size-1][0]==')')//如果为)则将数据将到(全部出栈入队
    {
        Popsign(stsign);
        while(stsign->sign[stsign->size-1][0]!='(')
        {
            e1=Popsign(stsign);
            printf("%c ",e1);
            n1=Calculate2(stnum,e1);
            Pushnum(stnum,n1);
        }
        Popsign(stsign);
    }
    else if(stsign->sign[stsign->size-1][0]=='#')//如果为#则将栈内数据全部出栈
    {
        Popsign(stsign);
        while(stsign->sign[stsign->size-1][0]!='#')
        {
            e1=Popsign(stsign);
            printf("%c ",e1);
            n1=Calculate2(stnum,e1);
            Pushnum(stnum,n1);
            e1='\0';
        }
        printf("\n");
        printf("the result is %d",n1);
    }
    else
    {
        while((stsign->sign[stsign->size-1][1])<=(stsign->sign[stsign->size-2][1])&&(stsign->sign[stsign->size-2][0]!='(')&&stsign->sign[stsign->size-2][0]!='#')//如果为正常运算符则进行优先级的比较,若下一个符号为(则直接存入
        {
            e1=Popsign(stsign);//刚刚进入栈的数据
            e2=Popsign(stsign);//将要存入后序序列的数据
            printf("%c ",e2);
            n1=Calculate2(stnum,e2);
            Pushnum(stnum,n1);
            Pushsign(stsign,e1);//将入栈数据存入栈内
            e1='\0';
            e2='\0';
        }
    }
}

三、最后就是整个程序的源代码了:
里面有很多关于栈的基本操作,在实际操作中没有用到,当时只是当作复习就敲出来。故到时阅读代码时发现有些自定义函数没用到就不必奇怪了。

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

#define MAX 1000

typedef struct stack
{
    char sign[MAX][2];//存储数据的数组,一列为数据域,一列为符号域。
    //符号域中,0表示该数据域存储的为数字,1表示为'-'或'+',2表示为'*'或'/',3表示为'(',4表示为')',-1'#'
    int num[MAX];
    int size;//栈顶指针
}stack,*pstack;//定义栈的结构体

pstack CreateStack();//创建栈
void DestroyStack(pstack st);//摧毁栈
void ClearStack(pstack st);//清空栈
int EmptyStack(pstack st);//判栈空
int LengthStack(pstack st);//判栈长
char GetTopsign(pstack st);//取栈顶元素
int GetTopnum(pstack st);//取栈顶元素
void Pushsign(pstack st,char d);//入栈
void Pushnum(pstack st,int d);//入栈
char Popsign(pstack st);//出栈
int Popnum(pstack st);//出栈a
void StackTravers(pstack st);//遍历栈
void renewdata_and_calculate(pstack stnum,pstack stsign,char b[MAX]);//将数据处理后再存储
void Calculate(pstack stnum,pstack stsign);//将表达式转化为逆波兰符号
int Calculate2(pstack stnum,char a);//计算表达式的值

int main()
{
    char a[MAX]={'/0'};
    pstack stnum;
    pstack stsign;
    stnum=CreateStack();
    stsign=CreateStack();
    ClearStack(stnum);
    ClearStack(stsign);
    printf("Please input the math expression and end it with '#' :\n");
    printf("Example: 3+2*(30+3)#\n");
    printf("if you want to use '(' and ')',please use them in English sign;\n");
    gets(a);
    renewdata_and_calculate(stnum,stsign,a);
    return 0;
}
pstack CreateStack()
{
    pstack st;//定义一个栈
    st=(pstack)malloc(sizeof(stack));//申请空间
    if(st)
    {
        memset(st->sign,0,sizeof(st->sign));
        memset(st->num,0,sizeof(st->num));
        return st;//返回数组的地址
    }
    else//申请空间失败
    {
        printf("Fall to apply space!\n");
        return NULL;
    }
}

void DestroyStack(pstack st)
{
    free(st->sign);//释放栈的空间
    free(st->num);
    st->size=0;//将栈的大小置为0
    st=NULL;//将栈指向NULL
    printf("Destorying stack success!\n");
}

void ClearStack(pstack st)
{
    memset(st->sign,0,sizeof(st->sign));//清空数组
    memset(st->num,0,sizeof(st->num));
    st->size=0;//将数组大小赋值为0
}

int EmptyStack(pstack st)
{
    if(st->size==0)
    {
        return 0;//栈为空
    }
    else
    {
        return 1;//栈不空
    }
}

int LengthStack(pstack st)
{
    return st->size;//返回栈长
}

char GetTopsign(pstack st)
{
    char e;
    e=st->sign[st->size-1][0];
    return e;//返回栈顶元素
}

int GetTopnum(pstack st)
{
    int e;
    e=st->num[st->size-1];
}
void Pushsign(pstack st,char d)
{
    st->sign[st->size][0]=d;//入栈
    if(d=='#')
    {
        st->sign[st->size][1]='-1';
    }
    else if(d=='+'||d=='-')
    {
        st->sign[st->size][1]='1';
    }
    else if(d=='*'||d=='/')
    {
        st->sign[st->size][1]='2';
    }
    else if(d=='(')
    {
        st->sign[st->size][1]='3';
    }
    else if(d==')')
    {
        st->sign[st->size][1]='4';
    }
    else
    {
        st->sign[st->size][1]='0';
    }
    st->size++;//栈顶指针加1
}

void Pushnum(pstack st,int d)//入栈
{
    st->num[st->size]=d;
    st->size++;
}
char Popsign(pstack st)
{
    char e;
    e=st->sign[st->size-1][0];//弹出
    st->sign[st->size-1][0]='\0';
    st->size--;//栈的大小减一
    return e;//返回弹出的元素
}

int Popnum(pstack st)
{
    int e;
    e=st->num[st->size-1];
    st->num[st->size-1]=0;
    st->size--;
    return e;
}

void StackTravers(pstack st)
{
    int i;
    for(i=0;i<st->size;i++)//遍历打印
    {
        printf("%d.%c ",i,st->sign[i][0]);
        printf("%d.%d ",i,st->num[i]);
    }
}

void renewdata_and_calculate(pstack stnum,pstack stsign,char b[MAX])
{
    int j,k=0;
    int e1=0;
    stsign->sign[stsign->size][0]='#';
    stsign->size++;
    for(j=0;b[j]!='#';j++)//判断b数组是否遍历完整
    {
        while(b[j]!='+'&&b[j]!='-'&&b[j]!='*'&&b[j]!='/'&&b[j]!='('&&b[j]!=')'&&b[j]!='#')//排除b[j]是运算符的可能
        {
            if((b[j]-'0')==0)//判断b[j]是否是0这个特殊数
            {
                e1=e1*10+b[j]-'0';//计算e1
                k++;//标记e1为特殊数0
            }
            else
            {
                e1=e1*10+b[j]-'0';//当e1不为0时,计算e1的数据
            }
            j++;//推动b数组遍历
        }
        if(e1!=0||k!=0)//判断是否是数字
        {
            Pushnum(stnum,e1);//存储数字
            printf("%d ",e1);
            if(b[j]!='#')
            {
                Pushsign(stsign,b[j]);//存储运算符
                Calculate(stnum,stsign);
            }
            else
            {
                Pushsign(stsign,b[j]);//存储运算符
                Calculate(stnum,stsign);
                j--;
            }
            k=0;//重新初始化标记数
            e1=0;//重新初始化计算的数据
        }
        else
        {
            Pushsign(stsign,b[j]);//存储运算符
            Calculate(stnum,stsign);
        }
    }
}

void Calculate(pstack stnum,pstack stsign)
{
    int n1;
    int i,j;
    char e1,e2;//用于暂时的存储数据
    if(stsign->sign[stsign->size-1][0]==')')//如果为)则将数据将到(全部出栈入队
    {
        Popsign(stsign);
        while(stsign->sign[stsign->size-1][0]!='(')
        {
            e1=Popsign(stsign);
            printf("%c ",e1);
            n1=Calculate2(stnum,e1);
            Pushnum(stnum,n1);
        }
        Popsign(stsign);
    }
    else if(stsign->sign[stsign->size-1][0]=='#')//如果为#则将栈内数据全部出栈
    {
        Popsign(stsign);
        while(stsign->sign[stsign->size-1][0]!='#')
        {
            e1=Popsign(stsign);
            printf("%c ",e1);
            n1=Calculate2(stnum,e1);
            Pushnum(stnum,n1);
            e1='\0';
        }
        printf("\n");
        printf("the result is %d",n1);
    }
    else
    {
        while((stsign->sign[stsign->size-1][1])<=(stsign->sign[stsign->size-2][1])&&(stsign->sign[stsign->size-2][0]!='(')&&stsign->sign[stsign->size-2][0]!='#')//如果为正常运算符则进行优先级的比较,若下一个符号为(则直接存入
        {
            e1=Popsign(stsign);//刚刚进入栈的数据
            e2=Popsign(stsign);//将要存入后序序列的数据
            printf("%c ",e2);
            n1=Calculate2(stnum,e2);
            Pushnum(stnum,n1);
            Pushsign(stsign,e1);//将入栈数据存入栈内
            e1='\0';
            e2='\0';
        }
    }
}

int Calculate2(pstack stnum,char a)
{
    char op;
    int num1,num2,num3;
    num2=Popnum(stnum);//出栈计算时的后一个元素
    num1=Popnum(stnum);//出栈计算时的前一个元素
    op=a;//选择计算方式
    switch(op)
    {
    case '+':
        num3=num1+num2;
        break;
    case '-':
        num3=num1-num2;
        break;
    case '*':
        num3=num1*num2;
        break;
    case '/':
        num3=num1/num2;
        break;
    default:
        break;
    }
    return num3;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值