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
#include
#include
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
#include
#include
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 /*包含头文件*/
#include
#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
#include
#include
#include
#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
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上的作者们的代码实践,自己也可以敲一个出来。