注:此高级计算器目前只有0~9的加减乘除复杂运算,含括号
思想:我们平常看到的运算符都是中缀表达式,如1+(2+3*4)-5
但是编译器是不认识这种表达式的,因此在编译的时候是要先转换成计算机能够识别的的表达式即后缀表达式,1234*++5-
因此高级计算器应有两个步骤:
1、将中缀表达式转换成为后缀表达式
2、规定计算规则,即怎么进行计算
首先我们来看看怎么将中缀表达式转换成为后缀表达式
对于一个中缀表达式,如1+(2+3*4)-5,转换应有以下几步(首先我们需要知道,此表达式在定义的时候是定义为字符数组)
1、将字符数组从左往右遍历
2、若当前字符为数字,则直接将此数字放入后缀表达式中(很显然后缀表达式也是一个字符数组,放入时是顺序放入)
3、若当前字符不为数字(也就是为运算符)(注:此计算器特别脆弱,不能包含非法字符,这只是学习栈所用的例子)
3.1若栈为空,则直接将当前字符入栈
3.2若不为空,判断是否为括号
3.2.1若为左括号(,则将当前字符直接入栈(注:对于左括号,除了栈已满情况都入栈,因此栈的容量要设置好)
3.2.2若为右括号),则将栈内元素逐个出栈,放入后缀表达式中,直到遇到左括号(。(注:右括号是不能入栈的, 而且左括号是不能放入后缀表达式中的,也就是说:若当前字符为右括号,开始判断栈顶元素是不是左括号,不 是就一直出栈,并放入后缀表达式,直到栈顶元素为左括号,停止,然后将左括号取出丢弃)
3.3栈不为空,当前元素也不为左右括号,则为运算符,对于运算符需要判断优先级,规则如下
3.3.1若当前运算符的优先级高于栈顶元素,则直接入栈(注,这里一定要注意高于这个词,也就是说,如果优先级 相当,不符合条件)
3.3.2若当前运算符的优先级不高于栈顶元素,则先需要先将栈顶元素出栈放入后缀表达式中,然后入栈(注:此部 分是一个循环,在将栈顶元素出栈后需要继续判定,不满足则继续出栈,满足则入栈)
注:此部分优先级的判断时,将括号视为最低优先级,只要栈顶元素为括号,直接入栈,栈中没有右括号
4、重复1、2、3步,直到遍历完成
5、最后将还在栈内的运算符出栈放入后缀表达式中
接下来我们来规定计算器的计算规则:
1、操作对象时后缀表达式,从左往右遍历
2、遇到数字直接进栈,否则取出栈顶和次栈顶进行运算,运算的结果要进栈
注:遇到数字直接进栈好理解,我们来仔细说说不是运算符的情况:
首先后缀表达式是数字在前,运算符在后,如1234*++5-,也就是说,前四次循环,直接将1234入栈,然后第五次循环, 当前字符为*,这时将栈顶元素4和次栈顶元素3取出,进行运算,即乘,然后将运算结果再放入栈中,此时栈内的元素为1、 2、12三个元素。运算是一定要搞清楚谁是被操作数,谁是操作数,3-4和4-3的结果是完全不同的,很显然,次栈顶元素是 被操作数,栈顶元素数操作数
3、重复1、2步,直到遍历完成
下面附上我写的代码,后缀表达式和计算在一个代码中,栈的相关操作在一个代码中,以及一个头文件声明
后缀表达式和计算:
#include<stdio.h>
#include<string.h>
#include"stack.h"
//此部分自己在写的时候有些混乱,不太好看
BOOL swap(char opr[],char opr1[])//opr是传递来的中缀表达式,opr1是返回的后缀表达式
{
stack a;
InitStack(&a);//初始化栈
int buf[MAXSIZE];//定义int是因为在定义栈时,栈内的元素定义为int,因此先定义一个int型数组,最后再将int型数组的元素赋给char类型数组
int i=0;
while(*opr!='\0')//遍历
{
if(*opr>='0'&&*opr<='9')//数字直接进入后缀表达式
{
buf[i++]=*opr;
}
else//运算符
{
if(*opr=='(')// ( 直接进栈,除非栈已满
{
if(FALSE==push(&a,*opr))
return FALSE;
}
else if(*opr==')')// ) 出栈,直到遇到(
{
while(a.buf[a.top]!='(')
{
pop(&a,&buf[i++]);
}
int b;
pop(&a,&b);// 扔掉(
}
else//不为()时
{
if(TRUE==IsEmpty(&a))//当栈为空,当前运算符直接进栈
{
push(&a,*opr);
}
else//栈不为空时,考虑优先级
{
if(*opr=='+'||*opr=='-')//+ -优先级最低,一直出栈到栈顶为(
while(FALSE==IsEmpty(&a)&&a.buf[a.top]!='(')
pop(&a,&buf[i++]);
else if(*opr=='*'||*opr=='/')//优先级最高,遇到+-进栈
while(a.buf[a.top]=='*'||a.buf[a.top]=='/')
pop(&a,&buf[i++]);
push(&a,*opr);
}
}
}
opr++;
}
while(TRUE!=IsEmpty(&a))//将栈内剩下的运算符出栈放入后缀表达式
pop(&a,&buf[i++]);
int j=0;
for(j=0;j<i;j++)//int数组转char数组
opr1[j]=buf[j];
opr1[j]='\0';
printf("%s\n",opr1);
}
//数组作形参:指针变量
BOOL calc(char opr[],int* result)//result是返回的结果
{
//定义栈空间
stack s;
InitStack(&s);
int value;
while(*opr!='\0')//从左往右遍历
{
if(*opr>='0'&&*opr<='9')//char转int
value=*opr-'0';
else//运算符
{
int opr1,opr2;
if(pop(&s,&opr2)==FALSE||pop(&s,&opr1)==FALSE)//判断出栈是否失败,失败直接结束函数,成功则将值赋给opr1 opr2,opr2是栈顶,opr1是次栈顶
return FALSE;
switch(*opr)
{
case '+':value=opr1+opr2;break;
case '-':value=opr1-opr2;break;
case '/':value=opr1/opr2;break;
case '*':value=opr1*opr2;break;
default:return FALSE;//出现非法字符
}
}
if(FALSE==push(&s,value))//入栈
return FALSE;
opr++;
}
if(pop(&s,result)==TRUE)
return TRUE;
else
return FALSE;
}
int main()
{
char opr[]="1+(2+3*4)/2";
swap(opr,opr);
printf("%s\n",opr);
int result=0;
calc(opr,&result);
printf("%d\n",result);
栈的相关函数:
#include"stack.h"
//定义函数
void InitStack(stack* p)
{
p->top=-1;
}
BOOL IsFull(stack* p)
{
if(MAXSIZE-1==p->top)
return TRUE;
return FALSE;
}
BOOL IsEmpty(stack* p)
{
if(-1==p->top)
return TRUE;
return FALSE;
}
BOOL push(stack* p,StackType data)
{
if(TRUE==IsFull(p))
return FALSE;
p->buf[++p->top]=data;
return TRUE;
}
BOOL pop(stack* p,StackType* data)
{
if(TRUE==IsEmpty(p))
return FALSE;
*data=p->buf[p->top--];
return TRUE;
}
头文件:
//定义结构体
typedef int StackType;
typedef char BOOL;
#define MAXSIZE 20
#define TRUE 1
#define FALSE 0
struct st
{
//容器
StackType buf[MAXSIZE];//栈顶容器
int top;//栈顶下标
};
typedef struct st stack;
//函数声明,函数的形参名可以省略
extern void InitStack(stack*);
extern BOOL IsFull(stack*);
extern BOOL IsEmpty(stack*);
extern BOOL push(stack*,StackType);
extern BOOL pop(stack*,StackType*);