栈的应用之表达式求值
前面我们实现了栈的顺序结构以及链式结构,现在我准备试一试用栈来实现表达式的求值。
使用栈的顺序结构作为基础,利用栈结构FILO的特点进行表达式的求值。
表达式包括起始符、结束符、数字、运算符、界限符这几个基本的元素,起始符和结束符可以自定义,但是不要数字、运算符、界限符重复,这里我是用了'#'来作为起始符和结束符。数字在我这里只实现了0-9,运算符为加(+)、减(-)、乘(*)、整除(/),更复杂的功能以后再根据需要来实现。界限符指的是左括号‘(’和右括号‘)’。
在这里我们需要了解一些关于ascii码存储各个运算符号以及数字的小知识点。下面列了一个表来直观的表示:
数字及运算符 | 十进制 | 十六进制 | 二进制 |
0 | 48 | 30 | 0011 0000 |
1 | 49 | 31 | 0011 0001 |
2 | 50 | 32 | 0011 0010 |
3 | 51 | 33 | 0011 0011 |
4 | 52 | 34 | 0011 0100 |
5 | 53 | 35 | 0011 0101 |
6 | 54 | 36 | 0011 0110 |
7 | 55 | 37 | 0011 0111 |
8 | 56 | 38 | 0011 1000 |
9 | 57 | 39 | 0011 1001 |
# | 35 | 23 | 0010 0011 |
* | 42 | 2A | 0010 1010 |
+ | 43 | 2B | 0010 1011 |
- | 45 | 2D | 0010 1101 |
/ | 47 | 2F | 0010 1111 |
( | 40 | 28 | 0010 1000 |
) | 41 | 29 | 0010 1001 |
这里我们需要注意一下的是每个数字或运算符对应的二进制形式,这是他们在计算机中存储的形式,当我们通过键盘输入的所有信息,当时用了getchar这个函数后,都被处理成一个一个的字符,例如输入23,处理起来就是2(00110010),3(00110011),这显然不是我们想要的结果,所以需要对这样的输入数据进行处理,例如通过一个int型变量来存储,将每一个char型数据赋予一定的权值,最后赋值给4个字节的int型变量。不过这样就需要另外再写一个函数了,本文只写到了0-9数字之间的带括号的加减乘除运算,至于实现更多数字的计算器功能,等后面再写吧。
编译环境vc++6.0,下面是完整的代码:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define SElemType int
#define STACK_INIT_SIZE 100
#define STACK_INCRECEMENT 10
#define STATUS int
#define ERROR 0
#define OK 1
#define null 0
#define TRUE 1
#define FALSE 0
typedef struct{
SElemType *top;
SElemType *base;
int stacksize;
}Stack;
STATUS Stack_Init(Stack *s)
{
s->base = (SElemType *)malloc(STACK_INIT_SIZE * sizeof(SElemType));
if(s->base == null)return ERROR;
s->top = s->base;
s->stacksize = STACK_INIT_SIZE;
return OK;
}
//若栈为空,返回TRUE,否则为FALSE
STATUS StackEmpty(Stack *s)
{
if(s->top == s->base)return TRUE;
else return FALSE;
return OK;
}
STATUS Pop(Stack *s,SElemType *e)
{
if(s->top == s->base)return ERROR;
*e = *--s->top;//栈顶指针一定要先自减,因为它始终在push入栈的最后一个数据之上
return OK;
}
STATUS Push(Stack *s,SElemType e)
{
if(s->top - s->base >=STACK_INIT_SIZE)
{
s->base = (SElemType *)realloc(s->base,(s->stacksize+STACK_INCRECEMENT)*sizeof(SElemType));
if(s->base == null)return ERROR;
s->top = s->base + s->stacksize;
s->stacksize += STACK_INCRECEMENT;
}
*s->top++ = e;
return OK;
}
int Gettop(Stack *s)
{
return *(s->top-1);
}
//比较两个运算符的优先级
char Precede(char a,char b)
{
if(a == '#')
{
if(b == '#')return '=';
else return '<';
}
if(a == ')')return '>';
if(a == '(')
{
if(b == ')')return '=';
else return '<';
}
if(a == '/')
{
if(b == '(')return '<';
else return '>';
}
if(a == '*')
{
if(b == '(')return '<';
else return '>';
}
if(a == '-')
{
if(b == '*'||b == '/'||b == '(')
return '<';
else return '>';
}
if(a == '+')
{
if(b == '*'||b == '/'||b == '(')return '<';
else return '>';
}
}
int Operate(int a, char theta,int b)
{
a &=0x0f;b &=0x0f;
switch(theta)
{
case '+':
return (a + b);break;
case '-':
return (a - b);break;
case '*':
return (a * b);break;
case '/':
return (a / b);break;
}
}
int main()
{
char theta;
int a,b,c;
Stack OPTR,OPND;
Stack_Init(&OPTR);
Push(&OPTR,'#');
Stack_Init(&OPND);
c=getchar();
while(c != '#' || Gettop(&OPTR) != '#')
{
if(isdigit(c))
{
Push(&OPND,c);
c=getchar();
}
else
switch(Precede((char)Gettop(&OPTR),(char)c))
{
case '<':
Push(&OPTR,c);c = getchar();
break;
case '=':
Pop(&OPTR,&c);c = getchar();
break;
case '>':
Pop(&OPTR,&theta);
Pop(&OPND,&b);
Pop(&OPND,&a);
Push(&OPND,Operate((int)a,(char)theta,(int)b));
break;
}
}
printf("%d\n",Gettop(&OPND));
}
当输入为:1+2*(3-1)#
输出结果为: