不带括号的表达式运算

这篇的目的一样是为了复习,有错误的地方还请大家指正(这里的代码部分也比较混乱,主要是记录思路了)。

---------------------------------------------------------------------------------------------------------------------------------

        在上学期的时候,我曾遇到过这样一道题:对给定的表达式(仅存在加减法)求值。当时的代码是这样的:

#include<stdio.h>
int main()
{
    float a,b;
    char x;
    scanf("%f",&a);
    while((x=getchar())!='\n')
    {
        scanf("%f",&b);
        switch(x){
        case'+':a=a+b;break;
        case'-':a-=b;break;
        case'*':a*=b;break;
        case'/':a/=b;break;
        };
    }
        printf("%f",a);
        return 0;
}

        这里仅仅需要使用一个switch和一个循环就能完成计算。但是这里便存在了一个问题:如果参与运算的符号不仅仅是加减法,而是优先级更高的乘除甚至次方,那么我们又该如何计算呢?由于计算的优先级问题,我们肯定不能只是进行简单的从左到右计算,我们需要判断出计算的先后。 

        为了解决这个问题,我们将使用栈这项数据结构。栈存储数据的特点为先进后出(First In Last Out),其定义大致如下:

typedef struct Stack
{
    int data[Max_Size];
    int top;//top是表示栈顶元素的下标
}stack;

          仔细研究计算表达式我们会发现,如果一个运算符优先级大于等于左右两边运算符的优先级,那么该运算符则会优先计算。(如下表)

1+2*3+4    2*3优先计算
1+2*3*4    2*3优先计算
1+2*3^4    2*3不能优先计算

         那么我们建立两个栈,一个栈来收集数据(即输入的数字),一个栈用来收集运算符。我们将表达式中的数字/运算符号逐个放入栈中,然后依次计算(即边将数字放入栈中边进行计算)。具体如下图所示。

         这里对栈的操作涉及初始化,进栈,出栈的操作,具体操作方式如下(由于运算符与数字的类型不一样,所以同一个操作我们需要写两个函数):

void InitStack(stackint *s)
{
    s->top= -1;
};//初始化的过程中,直接设置空栈
int push(stackint *s,int x)
{
    s->top = s->top+1;
    s->data[s->top]=x;
    return True;
};
int pop(stackint *s,int *x)
{
    *x=s->data[s->top];
    s->top--;
    return False;
};
void InitStack_char(stackchar *s)
{
    s->top= -1;
};
int push_char(stackchar *s,char x)
{
     s->top = s->top+1;
    s->data[s->top]=x;
    return True;
};
int pop_char(stackchar *s,char *x)
{
    *x=s->data[s->top];
    s->top--;
    return True;
};

        那么最终我们写出的代码为 : 

/*无括号运算表达式的值*/
/*表达式的优先级:1.^ 2. * / 3.+ - */
#include<stdio.h>
#include<stdlib.h>
#define True 1
#define False 0
#define Max_Size 50
typedef struct Stack_Int
{
    int data[Max_Size];
    int top;//top是表示栈顶元素的下标
}stackint;
typedef struct Stack_Char
{
    char data[Max_Size];
    int top;//top是表示栈顶元素的下标
}stackchar;
void InitStack(stackint *s);
int push(stackint *s,int x);
int pop(stackint *s,int *x);//这里pop函数的返回值的目的是判断函数是否成功
void InitStack_char(stackchar *s);
int push_char(stackchar *s,char x);
int pop_char(stackchar *s,char *x);
int compare(stackchar s);
int caculate(int x,int y);//x^y
int compute(int x,int y,char z);
int main()
{
    stackint si;
    stackchar sc;//当想要使用指针的时候一定要注意是否开辟了空间
    int x,z,i;//x为输入的数据,该程序里所有输入的数据都由栈来保存,故仅使用一个变量x//z接收吐出来的变量,类似垃圾桶//i为循环变量
    char y,q;//y的解释如上
    InitStack(&si);
    InitStack_char(&sc);
    push(&si,0);
    push_char(&sc,'+');//是栈中最底层的符号为优先级最低的'+'
    scanf("%d",&x);
    push(&si,x);
    while((y=getchar())!='\n')
    {
            push_char(&sc,y);
            scanf("%d",&x);
            push(&si,x);
            if(sc.data[sc.top]>=3)//当储存符号的栈内的元素超过三个时就开始判定
            {
                while(compare(sc) == 1)
                {
                    x=compute(si.data[si.top-2],si.data[si.top-1],sc.data[sc.top-1]);
                    sc.data[sc.top-1]=sc.data[sc.top];
                    pop_char(&sc,&q);
                    si.data[si.top-2]=x;
                    si.data[si.top-1]=si.data[si.top];
                    pop(&si,&z);
                }
            };           
    };
    /*完成最后内部的加减就可以了,可知最后的数字将比运算符号多一个*/
   for(i=sc.top;i>=0;i--)//注意判断条件不要搞错了
    {
         if(sc.data[i] == '*')
         {
            x=si.data[si.top]*si.data[si.top-1];
            pop(&si,&z);
            pop(&si,&z);
            push(&si,x);
         }else  if(sc.data[i] =='^')
         {
            x=caculate(si.data[si.top-1],si.data[si.top]);
             pop(&si,&z);
            pop(&si,&z);
            push(&si,x);
         }else if(sc.data[i] == '/')
         {
            x=si.data[si.top-1]/si.data[si.top];
            pop(&si,&z);
            pop(&si,&z);
            push(&si,x);
         }else if(sc.data[i] == '+')
        {
            x = si.data[si.top]+si.data[si.top-1];
            pop(&si,&z);
            pop(&si,&z);
            push(&si,x);
        }else{
            x=si.data[si.top-1]-si.data[si.top];
            pop(&si,&z);
            pop(&si,&z);
            push(&si,x);
        };
    };
    printf("%d",si.data[0]);
    return 0;
}
void InitStack(stackint *s)
{
    s->top= -1;
};//初始化的过程中,直接设置空栈
int push(stackint *s,int x)
{
    s->top = s->top+1;
    s->data[s->top]=x;
    return True;
};
int pop(stackint *s,int *x)
{
    *x=s->data[s->top];
    s->top--;
    return False;
};
void InitStack_char(stackchar *s)
{
    s->top= -1;
};
int push_char(stackchar *s,char x)
{
     s->top = s->top+1;
    s->data[s->top]=x;
    return True;
};
int pop_char(stackchar *s,char *x)
{
    *x=s->data[s->top];
    s->top--;
    return True;
};
int compare(stackchar s)//这个函数的作用是用来比较运算符的优先级,并且默认了栈中至少含有两个元素
{
   if((s.data[s.top-1]=='*' || s.data[s.top-1]== '/')&&(s.data[s.top]!='^'))
   {
    return True;
   }else if(s.data[s.top-1]=='^')
   {
    return True;
   }else
   {
    return False;
   }
};
int caculate(int x,int y)//x=0,y=5
{
    int n,i;
    for(n=1,i=0;i<y;i++)
    {
        n*=x;
    };
    return n;
};
int compute(int x,int y,char z)
{
    int result;
    if(z=='*')
    {
        result = x*y;
    }else if(z=='/')
    {
        result = x/y;
    }else if(z=='^')
    {
        result = caculate(x,y);
    };
    return result;
};

       这里面有几个比较特殊的地方:

1.每次进行运算的都是比+优先级更高的符号,等到最后我们只需要计算加法和减法即可。(即直接顺序进行即可)。

2.在边界的位置(栈底与栈顶)附近只有一个符号参与比较,由于栈顶难以处理(随时都在发生改变),故只能在循环结束后对其进行判断。但是对于栈底,我们加入一个“0+”,这样就能消去栈底的特殊性了。

 

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

只能看一眼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值