逆波兰计算器

逆波兰计算器的C语言实现

这个函数完成的功能:输入一个中缀表达式(支持负数和小数),输出相应的计算结果
例如:输入(1+3)*4+5.2/2#, 输出结果18.600000
(#代表表达式结束)

主要使用栈来实现操作。第一步将输入的中缀表达式转换为后缀表达式,存储在字符数组中;第二部计算后缀表达式

下面是代码,不足之处还望大佬指出


修改之后可以支持负数和小数的计算


// code

//逆波兰计算器
//支持负数和小数计算

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

#define STACK_INIT_SIZE 20
#define STACKINCREMENT 10
#define buffer_size 10 //缓存数字串的大小
#define STORESIZE 100  //存储后缀表达式的字符数组长度 如果过小需要手动扩容

typedef char ElemTypec;  //栈1元素为字符
typedef double ElemTyped;  //栈2元素为浮点数
typedef struct
{
    ElemTypec *base;
    ElemTypec *top;
    int stack_size;
}sqStack1; //栈1用来将中缀表达式转换为后缀表达式

typedef struct
{
    ElemTyped *base;
    ElemTyped *top;
    int stack_size;
}sqStack2;  //栈2用来计算后缀表达式


//初始化
void InitStack1(sqStack1 *s)
{
    s->base = (ElemTypec *)malloc(STACK_INIT_SIZE*sizeof(ElemTypec));
    if( !s->base)
    {
        exit(0);
        
    }
    
    s->top = s->base;
    s->stack_size = STACK_INIT_SIZE;
    
}

void InitStack2(sqStack2 *s)
{
    s->base = (ElemTyped *)malloc(STACK_INIT_SIZE*sizeof(ElemTyped));
    if( !s->base)
    {
        exit(0);
        
    }
    
    s->top = s->base;
    s->stack_size = STACK_INIT_SIZE;
    
}

//入栈
void Push1(sqStack1 *s, ElemTypec e)
{
    //自动扩容
    if(s->top - s->base >= s->stack_size)
    {
        s->base = (ElemTypec *)realloc(s->base, (s->stack_size + STACKINCREMENT)*sizeof(ElemTypec));
        if( !s->base)
        {
            exit(0);
                                          
        }
        s->top = s->base + s->stack_size;
        s->stack_size = s->stack_size + STACKINCREMENT;
        
                                      
    }
                                      
    *(s->top) = e;
    s->top++;
}
void Push2(sqStack2 *s, ElemTyped e)
{
    if(s->top - s->base >= s->stack_size)
    {
        s->base = (ElemTyped *)realloc(s->base, (s->stack_size + STACKINCREMENT)*sizeof(ElemTyped));
        if( !s->base)
        {
            exit(0);
            
        }
        s->top = s->base + s->stack_size;
        s->stack_size = s->stack_size + STACKINCREMENT;
        
        
    }
    
    *(s->top) = e;
    s->top++;
}

//出栈
void Pop1(sqStack1 *s, ElemTypec *e)
{
    if(s->top == s->base)
    {
        exit(0);
    }
    *e = *--(s->top);
    
}

void Pop2(sqStack2 *s, ElemTyped *e)
{
    if(s->top == s->base)
    {
        exit(0);
    }
    *e = *--(s->top);
    
}

//检查长度
long STACKLENGTH(sqStack1 s)
{
    return (s.top - s.base);
}

//存入后缀表达式的结果
void SaveChar(char *array, int *count, char c)
{
    array[*count] = c;
    (*count)++;
}

//获取后缀表达式用于计算
char GetChar(char *array, int *count)
{
    char c;
    c = array[*count];
    (*count)++;
    return c;
}
                                      




int main()
{
     //中缀表达式变为后缀表达式
    sqStack1 s;
    
    char c, e;
    int count = 0, flag = 0, minus_flag = 0;
    
    
    char string_store[STORESIZE];
    
    InitStack1(&s);
    
    printf("请输入中缀表达式,以#结束\n");
    printf("例如:(1+3)*4+5.2/2#\n");
    scanf("%c", &c);
    if(c == '-')  //第一个数为负数
    {
        SaveChar(string_store, &count, c);
        minus_flag = 1;
        
    }
    
    while(c != '#')
    {
        if(flag && c != '-')  //左括号下一个不是-号,把flag置0
        {
            flag = 0;
        }
        
        while((c >= '0' && c <= '9') || c == '.')
        {
            SaveChar(string_store, &count, c);
            scanf("%c", &c);
            if( !((c >= '0' && c <= '9') || c == '.'))
            {
                SaveChar(string_store, &count, ' ');
                break;
            }
            
        }
        

        
        if(c == ')')
        {
            Pop1(&s, &e);
            while(e != '(')
            {
                SaveChar(string_store, &count, e);
                SaveChar(string_store, &count, ' ');
                Pop1(&s, &e);
            }
        }
        
        else if(c == '+')
        {
            if(!STACKLENGTH(s))
            {
                Push1(&s, c);
            }
            else
            {
                do
                {
                    Pop1(&s, &e);
                    if(e == '(' )
                    {
                        Push1(&s ,e);
                    }
                    else
                    {
                        SaveChar(string_store, &count, e);
                        SaveChar(string_store, &count, ' ');
                        
                    }
                    
                }while(STACKLENGTH(s) && e != '(');
                Push1(&s, c);
                
            }
        }
        
        else if(c == '-')
        {
            if(minus_flag && flag == 0)
            {
                scanf("%c", &c);  //输入开头为负数,跳到下一次循环
                minus_flag = 0;
                continue;

                
            }
            
            if(!STACKLENGTH(s) && minus_flag == 0 && flag == 0) //栈为空且开头没有负号,说明是减号,把减号入栈
            {
                Push1(&s, c);
            }
            else
            {
                //如果前一个字符是(,那么下一个字符为-则必为负号
                if(flag)
                {
                    SaveChar(string_store, &count, '-');
                }
                
                
                do
                {
                    Pop1(&s, &e);
                    if(e == '(' )
                    {
                        Push1(&s ,e);
                    }
                    else
                    {
                        SaveChar(string_store, &count, e);
                        SaveChar(string_store, &count, ' ');
                        
                    }
                    
                }while(STACKLENGTH(s) && e != '(');
                if(flag == 0)
                {
                    Push1(&s, c);
                }
                else
                {
                    flag = 0;
                }
                
            }
        }
        
        
            

        else if('*' == c || '/' == c)
        {
            if(!STACKLENGTH(s))
            {
                Push1(&s, c);
            }
            else
            {
            
                Pop1(&s, &e);
                if(e == '+' || e == '-')
                {
                    Push1(&s, e);
                    Push1(&s, c);
                }
                else if(e == '*' || e == '/')
                {
                    SaveChar(string_store, &count, e);
                    SaveChar(string_store, &count, ' ');
                    Push1(&s, c);
                }
                else if(e == '(')
                {
                    Push1(&s, e);
                    Push1(&s, c);
                }
            }
        }
        
        else if(c == '(')
        {
            Push1(&s, c);
            flag = 1;
        }
            
        else if(c == '#')
        {
                break;
        }
        
        else
        {
            printf("输入有误\n");
        }
            
            scanf("%c", &c);
    };
    
    while(STACKLENGTH(s))
    {
        Pop1(&s, &e);
        SaveChar(string_store, &count, e);
        SaveChar(string_store, &count, ' ');
        
    }
    getchar();
    printf("\n");
    
    string_store[count] = '\0';
    printf("逆波兰表达式:%s\ncount:%d\n", string_store, count);
        
    
    //把后缀表达式计算出来
    sqStack2 s2;
    int i = 0;
    flag = 0;
    
    double sum1, sum2, temp;
    char buffer[buffer_size];
    char detect;
    
    InitStack2(&s2);
    count = 0;//count从头遍历

    c = GetChar(string_store, &count);
    while( c != '\0' )
    {
        //数字则入栈
        while(isdigit(c) || c == '.')
        {
            buffer[i++] = c;
            buffer[i] = '\0';
            if(i >= buffer_size-1)
            {
                printf("输入数据过大\n");
                return -1;
            }
            
            c = GetChar(string_store, &count);
            
            if( c == ' ')
            {
                temp = atof(buffer); //字符转换为数字
                if(flag)
                {
                    temp = -temp; //如果是负数
                    flag = 0;
                }
                Push2(&s2, temp);
                i = 0;
                
                break;
            }
        }
        
        
        //遇到操作符就运算
        switch ( c )
        {
                
            case ' ':
                break;
            case '+':
                Pop2(&s2, &sum1);
                Pop2(&s2, &sum2);
                Push2(&s2, sum1 + sum2);
                break;
                
            case '-':
                //读取到字符‘-’, 要检测是负号还是减号
                
                detect = GetChar(string_store, &count);
                if(detect == ' ') //下一个字符为空,则是减号 正常操作进行弹栈
                {
                    count--;
                    Pop2(&s2, &sum1);
                    Pop2(&s2, &sum2);
                    Push2(&s2, sum2 - sum1);
                }
                else if (isdigit(detect))  //下一个字符为数字,则是负号
                {
                    count--;
                    flag = 1;
                }
                
                break;
                
            case '*':
                Pop2(&s2, &sum1);
                Pop2(&s2, &sum2);
                Push2(&s2, sum1 * sum2);
                break;
                
            case '/':
                Pop2(&s2, &sum1);
                Pop2(&s2, &sum2);
                if(sum1 != .0)
                {
                    Push2(&s2, sum2 / sum1);
                }
                else
                {
                    printf("除数为0,错误");
                    return -1;
                }
                break;
                
            default:
                printf("非四则运算\n");
                return -1;
        }
        
        c = GetChar(string_store, &count);
        
    }
    Pop2(&s2, &sum1);
    printf("输出计算结果:%f\n", sum1);
    

        
    return 0;
        
}




下面是测试用例:
输入:3+2.5*2#
输出:8.000000 正确

输入:-3*2+5-2/8+(-2+5)*3+2#
输出:9.750000 正确

输入:-1.52.8+(-2.5-4)/23#
输出:-13.950000 正确

输入:-2.12*23+(-5.212+2.3)*3+((-2.1+3)*2+5)*1.1#
输出:-50.016 正确

输入:-2.12*23+(-5.212+2.3)*3+(-2.1+3)*2+5#
输出:-50.696000 正确

输入:-2.12245+(((23+1.1)+4.1)*2.4-(-1.1+3)/2)*2.1#
输出:-464.947000 正确

通过测试过程修正了代码,如果遇到了不正确的输出可以与我交流

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值