c语言数据结构——四则运算 简单

As we all know, c语言数据结构中的四则运算一直是一个常点,比较重要,是初学者一个必敲的代码,下面我罗列了四种数据结构四则运算,先从书(严老师)上到扩展;
严老师的数据结构上的四则运算思路是:

初始化OPTR与OPND栈(分别存储运算符号,数字),将表达式起始符 # 压入OPTR
当表达式没有扫描完毕或OPTR的栈顶元素不为#时,循环
若ch不是运算符,压入OPND,读入下一个字符;
若ch是,根据循环条件:OPTR的栈顶元素与优先级进行比较,做不同的处理
若是小于,ch压入OPTR,下一个
若是大于,弹出OPTR栈顶运算符,弹出OPND两个数,进行相应运算,压入OPND
若是对于,则OPTR栈顶元素是“(”且ch是 “)”,弹出OPTR栈顶“(”,即括号匹配成功,读入下一个

OPND栈顶元素即为表达式求值结果,返回此元素

其代码是:

char EvaluateExpression()
{
InitStack(OPTR);
InitStack(OPND);
push(OPTR,’#’);
cin>>ch;
while(ch!=’#’||GetTop(OPTR)!=’#’)
{
if(!In(ch))
{
push(OPND,ch);
cin>>ch;
}
else
switch(Precede(GetTop(OPTR),ch))
{
case’<’:
push(OPTR,ch);
cin>>ch;
break;
case’>’:
Pop(OPTR,theta);
Pop(OPND,a);Pop(OPND,b);
Push(OPND,Operate(a,theta,b));
break;
case’=’:
Pop(OPTR,x);
cin>>ch;
break;
}
}
return GetTop(OPND);
}

我们扩展一下就得到了一个能运行四则运算的正常代码:

#include <stdio.h>
#include <string.h> 
#include <stdlib.h>
char EvaluateExpression()
 {
 	InitStack(OPTR);
 	InitStack(OPND);
 	push(OPTR,'#');
 	cin>>ch;
 	while(ch!='#'||GetTop(OPTR)!='#')
 	{
 		if(!In(ch))
 		{
 			push(OPND,ch);
 			cin>>ch;
		}
		else
		  switch(Precede(GetTop(OPTR),ch))
		  {
		  	case'<':
		  		push(OPTR,ch);
		  		cin>>ch;
		  		break;
		  	case'>':
		  		Pop(OPTR,theta);
		  		Pop(OPND,a);Pop(OPND,b);
		  		Push(OPND,Operate(a,theta,b));
		  		break;
		  	case'=':
		  		Pop(OPTR,x);
		  		cin>>ch;
		  		break;
		  }
	 }
    return GetTop(OPND); 	
  }
 int main()
 {
 char a[];
 gets(a);
printf("%d",EvaluateExpression(a));
return 0;
} 
>

其中函数In是判定读入的字符ch是否为运算符,Precede是判定运算符栈的栈顶元素与读入的运算符之间优先关系的函数,Operate为进行一元运算的函数

我们从书上的思路再延申再扩展一下,就得到了下面的代码:

#include <stdio.h>
#include <string.h> 
#include <stdlib.h>
int Preemption(char a,char b)                           //符号优先级比较,a为当前读入,b为栈顶元素 
{
 int c;                                              //c反馈指令信息 0.结束 1.弹出 2.进栈 3.删除当前元素及栈顶元素 4.报错 
 switch(a)
 {
  case '#':if(b=='#') c=0;
           else c=1;break;
  case '+':if(b=='#'||b=='(') c=2;
           else c=1;break;
  case '-':if(b=='#'||b=='(') c=2;
           else c=1;break;
  case '*':if(b=='*'||b=='/') c=1;
           else c=2;break;
  case '/':if(b=='*'||b=='/') c=1;
           else c=2;break;
  case '(':c=2;break;
  case ')':if(b=='(') c=3;
     else c=1;break;
  default :c=4;break; 
 }
 return c;
} 
int main()
{
 char str[50]={"\0"};
 char *p=str;
 int *p3,*p4,a=0,b=0;
 char *p1,*p2;
 char stack1[20];                      //符号栈 栈顶指针p2,栈底指针p1 
 int stack2[20];                       //数字栈 栈顶指针p4,栈底指针p3 
 p1=p2=stack1;
 p3=p4=stack2;
 *p2++='#';
 
 gets(str);
 strcat(str,"#");
 while(*p!='\0')
 {
  if(*p<='9'&&*p>='0') 
  {
   a=a*10+(*p-'0');
   if(*(p+1)>'9'||*(p+1)<'0')
   {
    *p4++=a;
    a=0;
   }
   p++;
  }
  else
  {
   switch(Preemption(*p,*(p2-1)))
   {
    case 0:
      printf("%d\n",*p3);
      p++;
      break;
    case 1:
      b=*--p4;
      switch(*(--p2))
      {
       case '+':*(p4-1)=*(p4-1) + b;break;
       case '*':*(p4-1)=*(p4-1) * b;break;
       case '-':*(p4-1)=*(p4-1) - b;break;
       case '/':*(p4-1)=*(p4-1) / b;break;
      }
      break;
    case 2:
      *p2++=*p++;
      break;
    case 3:
      p++;
      p2--;
      break;
    case 4:
      printf("程序读到了无法计算的符号,出错了\n");
      p++;
      break;
   }
   } 
 }
 return 0;
}

下面的代码转载于:https://blog.csdn.net/zh3201/article/details/54619271
用到了后缀表达式思路,详细见文章末

#include <stdio.h>                          /*包含头文件*/  
#include <stdlib.h>

#define MAX_SIZE 1024                       /*数组长度*/  

int insert_operand(int *operand , int * top_num ,int num)             /*数据压入数据栈*/  
{
    (*top_num) ++;  
    operand[*top_num] = num;                    /*保存数据*/  
    
    return 0;                           /*正常退出*/  
}  

int insert_oper (char * oper , int *top_oper , char ch)             /*操作符压入符号栈*/  
{  
    (*top_oper)++;  
    oper[*top_oper] = ch;                       /*保存操作符*/  
    return 0;                           /*正常退出*/  
}  
     
int compare(char *oper , int *top_oper , char ch)                   /*比较操作服优先级*/  
{     
    if((oper[*top_oper] == '-' || oper[*top_oper] == '+')           /*判断当前优先级是否比栈顶操作符优先级高*/  
    && (ch == '*' || ch == '/'))
    {  
        return 0;                      /*操作符压入栈*/   
    }   
    else if(*top_oper == -1 || ch == '('|| (oper[*top_oper] == '(' && ch != ')'))  /*判断操作符栈是否为空;栈顶操作   符是否为'('*/  
    {  
return 0;                       /*操作符压入栈*/  
    }  
    else if (oper[*top_oper] =='(' && ch == ')' )       /*判断括号内的表达式是否计算完毕*/  
    {  
(*top_oper)--;  
return 1;                       /*对()进行处理*/  
    }  
    else  
    {  
        return -1;                                          /*进行操作符的运算*/  
    }  
}  


int deal_date(int *operand ,char *oper ,int *top_num, int *top_oper)    /*进行数据运算*/  
{  
    int num_1 = operand[*top_num];              /*取出数据栈中两个数据*/  
    int num_2 = operand[*top_num - 1];  
    
    int value = 0;  
    
    if(oper[*top_oper] == '+')                  /*加法操作*/  
    {  
value = num_1 + num_2;  
    }  
    
    else if(oper[*top_oper] == '-')             /*减法操作*/  
    {  
value = num_2 - num_1;  
    }  
    
    else if(oper[*top_oper] == '*')             /*乘法操作*/  
    { 
        value = num_2 * num_1;  
    }  
    
    else if(oper[*top_oper] == '/')             /*除法操作*/  
    {  
value = num_2 / num_1;  
    }  
    
    (*top_num) --;                              /*将数据栈顶下移一位*/  
    operand[*top_num] = value;                  /*将得到的值压入数据栈*/  
    (*top_oper) --;                             /*将操作符栈顶下移一位*/  
}  

//以上都是压入;下面开始拿出运算; 
int main()  
{  
    int operand[MAX_SIZE] = {0};                /*数据栈,初始化*/  
    int  top_num = -1;  
    
    char oper[MAX_SIZE] = {0};                  /*操作符栈,初始化*/  
    int top_oper = -1;  
    char *str = (char *) malloc (sizeof(char) * 100);               /*获取表达式(不带=)*/  
    
    scanf("%s",str);  
    char* temp;  
    char dest[MAX_SIZE];  
    
    int num = 0;  
    int i = 0;  
    
    while(*str != '\0')  
    {  
temp = dest;  
while(*str >= '0' && *str <= '9')           /*判断是否是数据*/  
        {  
   *temp = *str;  
   str ++;  
   temp ++;                  
}                               /*遇到符号退出*/  
       
        if(*str != '(' && *(temp - 1) != '\0')      /*判断符号是否为'('*/  
{  
   *temp = '\0';  
   num = atoi(dest);               /*将字符串转为数字*/  
   insert_operand(operand, &top_num,num);      /*将数据压入数据栈*/  
}  

while(1)  
{  
   i = compare(oper,&top_oper,*str);      /*判断操作符优先级*/  
   if(i == 0)  
   {  
       insert_oper(oper,&top_oper,*str);   /*压入操作符*/  
       break;  
   }  
   
   else if(i == 1)                         /*判断括号内的表达式是否结束*/  
   {  
str++;
   }  
   
   else if(i == -1)                        /*进行数据处理*/  
   {  
deal_date(operand,oper,&top_num,&top_oper);  
   }  
}  
        str ++;                 /*指向表达式下一个字符*/  
    }  
    
    printf("num = %d\n",operand[0]);        /*输出结果*/  
    return 0;                       /*正常退出*/  
}

还有下面的这种思路:
(作者忘了是谁,如有侵犯,联系必删)

//说明:只能进行10以内整数的加减乘除,并且表达式的值要以“#”结尾
#include <malloc.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define TRUE 1
#define FALSE 0
#define ERROR 0
#define OK 1
#define STACK_INIT_SIZE 100 //存储空间初始分配量//
#define STACKINCREMENT 10   //存储空间分配增量//

typedef char SElemType;
typedef int Status;
char a[][7]={
    {'>','>','<','<','<','>','>'},
    {'>','>','<','<','<','>','>'},
    {'>','>','>','>','<','>','>'},
    {'>','>','>','>','<','>','>'},
    {'<','<','<','<','<','=',' '},
    {'>','>','>','>',' ','>','>'},
    {'<','<','<','<','<',' ','='}
};
/*char a[][]={
    {'>','>','>','>','<','>','<'},
    {'>','>','>','>','<','>','<'},
    {'<','<','>','>','<','>','<'},
    {'<','<','>','>','<','>','<'},
    {'<','<','<','<','<',' ','<'},
    {'>','>','>','>','=','>',' '}, 
    {'>','>','>','>',' ','>','='}
};*/
char OP[7]={'+','-','*','/','(',')','#'};
typedef struct
{
    SElemType* base;  //在栈构造之前和销毁之后,base的值为NULL//
    SElemType* top;   //栈顶指针//
    int stacksize;    //当前已分配的存储空间,以元素为单位//
}SqStack;
//构造一个空栈S//
int InitStack(SqStack &S)
{
    S.base=(SElemType*)malloc(STACK_INIT_SIZE *sizeof(SElemType));
    if(!S.base)
        exit(ERROR);  //存储分配失败//
    S.top=S.base;
    S.stacksize =STACK_INIT_SIZE;
    return OK;
}
Status GetTop(SqStack S)
{   //若栈不为空,则用e返回S的栈顶元素,并返回OK,否则返回ERROR//
    if(S.top==S.base)
        return ERROR;

    return *(S.top-1);
}
//插入元素//
int Push(SqStack &S, SElemType e)
{   //插入元素e为新的栈顶元素//
    if(S.top-S.base>=S.stacksize)
    {    //栈满,追加存储空间//
        S.base=(SElemType*)realloc(S.base,(S.stacksize+STACKINCREMENT)*sizeof(SElemType));
        if(!S.base)
            exit(ERROR);  //存储分配失败//
        S.top=S.base+S.stacksize;
        S.stacksize+=STACKINCREMENT;
    }
    *S.top++=e;
    return OK;
}
int Pop(SqStack &S, SElemType &e)
{  //若栈不为空,则删除S的栈顶元素,用e返回其值,并返回//
    if(S.top==S.base)
        return ERROR;
    e=*(--S.top);
    return OK;
}
//检查是否为空栈//
int EmptyStack(SqStack &S)
{
    if(S.top==S.base)
        return 1;
    else
        return 0;
}
/*int ListTraverse(SqStack S,Status(*visit)(SElemType))
{
    SElemType *p;
    p=S.base;
    for(p=S.base;p<S.top;p++)
        (*visit)(*p);
    return OK;
}*/

int Precede(char c1,char c2)
{
    int i,j;
    switch(c1)
    {
    case'+':i=0;
        break;
    case'-':i=1;
        break;
    case'*':i=2;
        break;
    case'/':i=3;
        break;
    case'(':i=4;
        break;
    case')':i=5;
        break;
    case'#':i=6;
        break;
    }
    switch(c2)
    {
    case'+':j=0;
        break;
    case'-':j=1;
        break;
    case'*':j=2;
        break;
    case'/':j=3;
        break;
    case'(':j=4;
        break;
    case')':j=5;
        break;
    case'#':j=6;
        break;
    }

    return a[i][j];
}
int Operate(char a,char theta,char b)
{
    char result,i,j;
    i=a-48;
    j=b-48;
    switch(theta)
    {
    case'+':result=i+j+48;break;//因为数值是char型,所以要将0~9的ASCII码值转化为数值,进行计算后再转为ASCII码值存储
    case'-':result=i-j+48;break;
    case'*':result=(i*j)+48;break;
    case'/':result=(i/j)+48;break;
    }
    return result;
}
int In(char c,char OP[])
{
    int i,f=0;
    for(i=0;i<7;i++)
    {
        if(c==OP[i])
        {
            f=1;
        break;  
        }
    }
    if(f==0)
        return 0;
    else return 1;
}
//表达式求值//
int EvaluateExpression()
{
//  int a,b,c;
    char a,b,c,r;
    char theta,x;
    SqStack OPTR;
    SqStack OPND;
    InitStack(OPTR);
    Push(OPTR,'#');
    InitStack(OPND);
    c=getchar();
    while(c!='#'||GetTop(OPTR)!='#')
    {
        if(!In(c,OP))
        {
            Push((OPND),c);
            c=getchar();
        }
        else
        switch(Precede(GetTop(OPTR),c))
        {
            case'<':
                Push(OPTR,c);
                c=getchar();
                break;//1+2#:如加上printf("1234%c\n",c)语句可以看到c为+号
            case'=':
                Pop(OPTR,x);
                c=getchar();break;
            case'>':
                Pop(OPND,b);
                Pop(OPTR,theta);
                Pop(OPND,a);
                Push(OPND,Operate(a,theta,b));
                break;//theta未取到栈顶元素,即在1+2的过程中theta未取到+号
        }
    }
    r=GetTop(OPND)-48;//将数值由ASCII码值转化为十进制的数值
    return r;
}
int main()
{
    int c;
    printf("请输入需要计算的表达式:\n");
    c=EvaluateExpression();
    printf("result=%d\n",c);
} 

除了书上的思路外,还有一种波兰式、逆波兰式的表达式求值的方法,其大体思路见:
https://blog.csdn.net/linraise/article/details/20459751
以及
https://blog.csdn.net/qq_42412605/article/details/81262956
这两位作者的博客都不错

其实在我看来数据结构用栈实现四则运算的过程都大同小异,无非是一个如何将一些字符压栈入栈的问题,理解了之后,再根据书上的理论与scdn上的作者们的代码实践,自己也可以敲一个出来。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

四夕兴言

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

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

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

打赏作者

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

抵扣说明:

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

余额充值