栈与队列(四)中缀计算器代码

中缀计算器(先中缀转后缀,再RPN计算)

关于代码想说的:

1.有人会问为什么要做两个栈         解决:因为在中缀转后缀中第一个栈被销毁的

2.缓冲量的作用            解决:接收空格

3.如何结合中缀转后缀和RPN计算       解决:将中缀转后追的输出放进数组string中,然后在RPN计算中本来要输入的直接在数组里拿就好,注意不要忘记空格


/*************************************************************************
    > File Name: 中缀计算器.c
    > Author: geeker
    > Mail: 932834897@qq.com
    > Created Time: 2017年02月08日 星期三 15时32分41秒
 ************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <math.h>
#include <ctype.h>

#define stacksize 20//栈的最大容量
#define maxbuffer 10//缓冲量

char string[50];//定义一个字符数组,将中缀转后缀的输出数据放到数组中,再取数组元素进行逆波兰计算

typedef char ElemType;//19-25行是给中缀转后缀用的
typedef struct
{
    ElemType *base;
    ElemType *top;
    int maxsize;
}sqStack;

typedef double bElemType;//28-33行是给逆波兰计算用的
typedef struct
{
    bElemType *base;
    bElemType *top;
    int maxsize;
}bsqStack;

void InitStack(sqStack *s)//初始化
{
    s->base=(ElemType *)malloc(stacksize * sizeof(ElemType));
    if(!s->base)//分配失败退出程序
   {
       exit(0);
   }
    s->top=s->base;
    s->maxsize=stacksize;
}

void Push(sqStack *s,ElemType e)//压栈
{
    if(s->top-s->base>=s->maxsize)
    {
        return;
    }
    *(s->top)=e;//给当前栈顶赋值
    s->top++;//栈顶元素加1
}

void Pop(sqStack *s,ElemType *e)//出栈
{
    if(s->top==s->base)
    {
        return;
    }
    *e=*--(s->top);
}

int StackLen(sqStack s)//计算容量
{
    return(s.top-s.base);
}

void bInitStack(bsqStack *s)//再次初始化(为什么要再次初始化、压栈等等,因为在中转后的change函数中已经把栈给销毁了,所以要重新建立)
{
    s->base=(bElemType *)malloc(stacksize * sizeof(bElemType));
    if(!s->base)
    {
        exit(0);
    }
    s->top=s->base;
    s->maxsize=stacksize;
}

void bPush(bsqStack *s,bElemType e)//再次压栈
{
    if(s->top-s->base>=s->maxsize)
    {
        return;
    }
    *(s->top)=e;
    s->top++;
}

void bPop(bsqStack *s,bElemType *e)//再次出栈
{
    if(s->top==s->base)
    {
        return;
    }
    *e=*--(s->top);
}

int bStackLen(bsqStack s)//再次求栈容量
{
    return(s.top-s.base);
}

void DestroyStack(sqStack *s)//销毁栈
{
    free(s->base);
    s->base=s->top=NULL;
    s->maxsize=0;
}

void DestroyBStack(bsqStack *s)//再次销毁栈
{
    free(s->base);
    s->base=s->top=NULL;
    s->maxsize=0;
}

int change()//就是中缀转后缀的一个函数,然而区别就在于将输出的数据存入到string数组中,所以每一次printf就会跟string[i++];
{
    sqStack s;
    char c,e;

    InitStack(&s);

    int i=0;

    printf("请输入中缀表达式,以#为结束标志\n");
    scanf("%c",&c);

    while(c!='#')
    {
        while(c>='0'&&c<='9')
        {
            printf("%c",c);
            string[i++]=c;//关键。。把输出的数据放到数组中
             scanf("%c",&c);
            if(c<'0'||c>'9')
            {
                printf(" ");
                string[i++]=' ';
            }
        }
        if(')'==c)
        {
            Pop(&s,&e);
            while('('!=e){
                printf("%c ",e);
                string[i++]=e;
                string[i++]=' ';
                Pop(&s,&e);
            }
        }
        else if('+'==c||'-'==c)
        {
            if(!StackLen(s))
            {
                Push(&s,c);
            }
            else
            {
                do
                {
                    Pop(&s,&e);
                    if('('==e)
                    {
                        Push(&s,e);
                    }
                    else
                    {
                        printf("%c",e);
                            string[i++]=e;
                    }
                }while(StackLen(s)&&'('!=e);
                Push(&s,c);
            }
        }
        else if('*'==c||'/'==c||'('==c)
        {
            Push(&s,c);
        }
        else if('#'==c)
        {
            break;
        }
        else
        {
            printf("\n出错,程序输入错误\n");
            return -1;
        }
        scanf("%c",&c);
    }
        while(StackLen(s))
        {
            Pop(&s,&e);
        printf("%c ",e);
            string[i++]=e;
            string[i++]=' ';
        }
        printf("\n");
        string[i]='\0';
        printf("%s\n",string);
        string[i]='#';//这里特别重要,很容易忘记,忘记了很难找到错误,切记!
        DestroyStack(&s);
        return 0;
}

int main()//这个main函数其实就是一个逆波兰计算器,区别就是将数组中的数据当做本来要输入的字符,即char *p=string;c=*p++;然后c就是那个看做输入的字符,逆波兰在前面的博客已经有算法,不多解释
{
    bsqStack s;
    char c;
    double d,e;
    char str[maxbuffer];//缓冲
    int f=0;

    change();
    bInitStack(&s);
    printf("请按逆波兰表达式输入带计算数据,数据与运算符之间用空格隔开,以#作为结束标志\n");
    char *p=string;//关键
    c=*p++;
    while(c!='#')
    {
        
        while(isdigit(c)||c=='.')
        {
            str[f++]=c;
            str[f]='\0';
            if(f>=10)
            {
                printf("error,输入单个数据过大\n");
                return -1;
            }//缓冲区最大范围
        //    scanf("%c",&c)
            c=*p++;//这里本来是输入的,但所有数据已存在数组中
            if(c==' ')
            {
                d=atof(str);//功能
                bPush(&s,d);
                f=0;
                break;
            }
        }
        switch(c)
        {
            case'+':
                bPop(&s,&e);
                bPop(&s,&d);
                bPush(&s,d+e);
                break;
            case'-':
                bPop(&s,&e);
                bPop(&s,&d);
                bPush(&s,d-e);
                break;
            case'*':
                bPop(&s,&e);
                bPop(&s,&d);
                bPush(&s,d*e);
                break;
            case'/':
                bPop(&s,&e);
                bPop(&s,&d);
                if(e!=0)
                {
                    bPush(&s,d/e);
                }
                else
                {
                    printf("\nerror,除数不能为0\n");
                    return -1;
                }
                break;
        }
    //    scanf("%c",&c);
        c=*p++;
    }
    bPop(&s,&d);
    printf("\n最终计算结果为: %lf\n",d);
    DestroyBStack(&s);//别忘记销毁栈
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值