栈的应用举例--表达式求值(第三章 P53 算法3.4)

栈的应用举例--表达式求值

我们仅讨论简单算术表达式的求值问题,这种表达式只含加、减、乘、除 4 种运算符。

算符间的优先无关系:

  + - * / ( ) #
+ > > < < < > >
- > > < < < > >
* > > > > < > >
/ > > > > < > >
( < < < < < =  
) > > > >   > >
# < < < < <   =

为实现算符优先算法,可以使用两个工作栈。一个称做 OPTR,用以寄存运算符;另一个称做 OPND ,用以寄存操作数或运算结果。

算法基本思想:

(1)首先置操做数栈为空栈,表达式起始符 “#” 为运算符栈的栈底元素。

(2)依次读入表达式中的每个字符,若是操作数则进 OPND 栈,若是运算符则和 OPTR 栈的栈顶运算符比较优先权后作相应操作,直到整个表达式求值完毕(即 OPTR 栈的栈顶元素和当前读入的字符均为 “#”)。


typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
typedef int Boolean; /* Boolean是布尔类型,其值是TRUE或FALSE */
typedef char SElemType; /* 定义栈元素的类型 */

#include<malloc.h> /* malloc()等 */
#include<stdio.h> /* EOF(=^Z或F6),NULL */
#include<process.h> /* exit() */

/* 函数结果状态代码 */
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2 

/* --------------------------   栈的顺序存储表示   -----------------------------*/

#define STACK_INIT_SIZE 10 /* 存储空间初始分配量 */
#define STACKINCREMENT 2 /* 存储空间分配增量 */
typedef struct SqStack
{
	SElemType *base; /* 在栈构造之前和销毁之后,base的值为NULL */
	SElemType *top; /* 栈顶指针 */
	int stacksize; /* 当前已分配的存储空间,以元素为单位 */
}SqStack; /* 顺序栈 */

/* ----------------------------------------------------------------------------*/


Status visit(SElemType c)
{
	printf("%d ", c);
	return OK;
}


/* ---------------------------------   需要用到的顺序栈基本操作  ------------------------------------*/

Status InitStack(SqStack *S)
{ /* 构造一个空栈S */
	(*S).base = (SElemType *)malloc(STACK_INIT_SIZE * sizeof(SElemType));
	if (!(*S).base)
		exit(OVERFLOW); /* 存储分配失败 */
	(*S).top = (*S).base;
	(*S).stacksize = STACK_INIT_SIZE;
	return OK;
}

Status GetTop(SqStack S, SElemType *e)
{ /* 若栈不空,则用e返回S的栈顶元素,并返回OK;否则返回ERROR */
	if (S.top > S.base)
	{
		*e = *(S.top - 1);
		return OK;
	}
	else
		return ERROR;
}

Status 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(OVERFLOW); /* 存储分配失败 */
		(*S).top = (*S).base + (*S).stacksize;
		(*S).stacksize += STACKINCREMENT;
	}
	*((*S).top)++ = e;
	return OK;
}

Status Pop(SqStack *S, SElemType *e)
{ /* 若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR */
	if ((*S).top == (*S).base)
		return ERROR;
	*e = *--(*S).top;
	return OK;
}




/* -------------------------------------------------------------------------------------------------*/

/* 表达式求值(输入、输出和中间结果均只能是0~9) */

SElemType Precede(SElemType t1, SElemType t2)
{ /* 根据教科书表3.1,判断两符号的优先关系 */
	SElemType f;
	switch (t2)
	{
	case '+':
	case '-':if (t1 == '(' || t1 == '#')
		f = '<';
			 else
		f = '>';
		break;
	case '*':
	case '/':if (t1 == '*' || t1 == '/' || t1 == ')')
		f = '>';
			 else
		f = '<';
		break;
	case '(':if (t1 == ')')
	{
		printf("ERROR1\n");
		exit(ERROR);
	}
			 else
		f = '<';
		break;
	case ')':switch (t1)
	{
	case '(':f = '=';
		break;
	case '#':printf("ERROR2\n");
		exit(ERROR);
	default: f = '>';
	}
			 break;
	case '#':switch (t1)
	{
	case '#':f = '=';
		break;
	case '(':printf("ERROR3\n");
		exit(ERROR);
	default: f = '>';
	}
	}
	return f;
}

Status In(SElemType c)
{ /* 判断c是否为运算符 */
	switch (c)
	{
	case'+':
	case'-':
	case'*':
	case'/':
	case'(':
	case')':
	case'#':return TRUE;
	default:return FALSE;
	}
}

SElemType Operate(SElemType a, SElemType theta, SElemType b)
{
	switch (theta)
	{
	case'+':
		return a + b;
	case'-':
		return a - b;
	case'*':
		return a * b;
	}
	return a / b;
}

SElemType EvaluateExpression() /* 算法3.4 */
{ /* 算术表达式求值的算符优先算法。设OPTR和OPND分别为运算符栈和运算数栈 */
	SqStack OPTR, OPND;
	SElemType a, b, c, x, theta;
	InitStack(&OPTR);
	Push(&OPTR, '#');
	InitStack(&OPND);
	c = getchar();
	GetTop(OPTR, &x);
	while (c != '#' || x != '#')
	{
		if (In(c)) /* 是7种运算符之一 */
			switch (Precede(x, c))
			{
			case'<':Push(&OPTR, c); /* 栈顶元素优先权低 */
				c = getchar();
				break;
			case'=':Pop(&OPTR, &x); /* 脱括号并接收下一字符 */
				c = getchar();
				break;
			case'>':Pop(&OPTR, &theta); /* 退栈并将运算结果入栈 */
				Pop(&OPND, &b);
				Pop(&OPND, &a);
				Push(&OPND, Operate(a, theta, b));
				break;
			}
		else if (c >= '0'&&c <= '9') /* c是操作数 */
		{
			Push(&OPND, c-48);
			c = getchar();
		}
		else /* c是非法字符 */
		{
			printf("ERROR4\n");
			exit(ERROR);
		}
		GetTop(OPTR, &x);
	}
	GetTop(OPND, &x);
	return x;
}

void main()
{
	printf("请输入算术表达式(中间值及最终结果要在0~9之间),并以#结束\n");
	printf("%d\n", EvaluateExpression());
}

运行结果:

下面的程序做了些改进,把连续输入的几个数值型字符作为一个整数处理,使数值范围扩大为整数,更具有

实用性。

而且原本课本上以 “#” 表示算式输入结束,以下改为 “=” ,这样更加贴合实际。


typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
typedef int Boolean; /* Boolean是布尔类型,其值是TRUE或FALSE */
typedef int SElemType; /* 栈元素类型为整型,改进算法3.4 */; /* 定义栈元素的类型 */

#include<malloc.h> /* malloc()等 */
#include<stdio.h> /* EOF(=^Z或F6),NULL */
#include<process.h> /* exit() */

/* 函数结果状态代码 */
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2 

/* --------------------------   栈的顺序存储表示   -----------------------------*/

#define STACK_INIT_SIZE 10 /* 存储空间初始分配量 */
#define STACKINCREMENT 2 /* 存储空间分配增量 */
typedef struct SqStack
{
	SElemType *base; /* 在栈构造之前和销毁之后,base的值为NULL */
	SElemType *top; /* 栈顶指针 */
	int stacksize; /* 当前已分配的存储空间,以元素为单位 */
}SqStack; /* 顺序栈 */

/* ----------------------------------------------------------------------------*/


Status visit(SElemType c)
{
	printf("%d ", c);
	return OK;
}


/* ---------------------------------   需要用到的顺序栈基本操作  ------------------------------------*/

Status InitStack(SqStack *S)
{ /* 构造一个空栈S */
	(*S).base = (SElemType *)malloc(STACK_INIT_SIZE * sizeof(SElemType));
	if (!(*S).base)
		exit(OVERFLOW); /* 存储分配失败 */
	(*S).top = (*S).base;
	(*S).stacksize = STACK_INIT_SIZE;
	return OK;
}

Status GetTop(SqStack S, SElemType *e)
{ /* 若栈不空,则用e返回S的栈顶元素,并返回OK;否则返回ERROR */
	if (S.top > S.base)
	{
		*e = *(S.top - 1);
		return OK;
	}
	else
		return ERROR;
}

Status 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(OVERFLOW); /* 存储分配失败 */
		(*S).top = (*S).base + (*S).stacksize;
		(*S).stacksize += STACKINCREMENT;
	}
	*((*S).top)++ = e;
	return OK;
}

Status Pop(SqStack *S, SElemType *e)
{ /* 若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR */
	if ((*S).top == (*S).base)
		return ERROR;
	*e = *--(*S).top;
	return OK;
}




/* -------------------------------------------------------------------------------------------------*/

SElemType Precede(SElemType t1, SElemType t2) /* 同上 */
{ /* 根据教科书表3.1,判断两符号的优先关系 */
	SElemType f;
	switch (t2)
	{
	case '+':
	case '-':if (t1 == '(' || t1 == '=')
		f = '<';
			 else
		f = '>';
		break;
	case '*':
	case '/':if (t1 == '*' || t1 == '/' || t1 == ')')
		f = '>';
			 else
		f = '<';
		break;
	case '(':if (t1 == ')')
	{
		printf("ERROR1\n");
		exit(ERROR);
	}
			 else
		f = '<';
		break;
	case ')':switch (t1)
	{
	case '(':f = '=';
		break;
	case '=':printf("ERROR2\n");
		exit(ERROR);
	default: f = '>';
	}
			 break;
	case '=':switch (t1)
	{
	case '=':f = '=';
		break;
	case '(':printf("ERROR2\n");
		exit(ERROR);
	default: f = '>';
	}
	}
	return f;
}

Status In(SElemType c) /* 几乎与上相同 */
{ /* 判断c是否为运算符 */
	switch (c)
	{
	case'+':
	case'-':
	case'*':
	case'/':
	case'(':
	case')':
	case'=':return TRUE; /* 此句不同于上 */
	default:return FALSE;
	}
}

SElemType Operate(SElemType a, SElemType theta, SElemType b) /* 有改动 */
{
	SElemType c;
	switch (theta)
	{
	case'+':c = a + b;
		break;
	case'-':c = a - b;
		break;
	case'*':c = a * b;
		break;
	case'/':c = a / b;
	}
	return c;
}

SElemType EvaluateExpression() /* 有改动 */
{ /* 算术表达式求值的算符优先算法。设OPTR和OPND分别为运算符栈和运算数栈 */
	SqStack OPTR, OPND;
	SElemType a, b, d, x, theta;
	char c; /* 存放由键盘接收的字符串 */
	char z[6]; /* 存放整数字符串 */
	int i;
	InitStack(&OPTR); /* 初始化运算符栈 */
	Push(&OPTR, '='); /* =是表达式结束标志 */
	InitStack(&OPND); /* 初始化运算数栈 */
	c = getchar();
	GetTop(OPTR, &x);
	while (c != '=' || x != '=')
	{
		if (In(c)) /* 是7种运算符之一 */
			switch (Precede(x, c))
			{
			case'<':Push(&OPTR, c); /* 栈顶元素优先权低 */
				c = getchar();
				break;
			case'=':Pop(&OPTR, &x); /* 脱括号并接收下一字符 */
				c = getchar();
				break;
			case'>':Pop(&OPTR, &theta); /* 退栈并将运算结果入栈 */
				Pop(&OPND, &b);
				Pop(&OPND, &a);
				Push(&OPND, Operate(a, theta, b));
			}
		else if (c >= '0'&&c <= '9') /* c是操作数 */
		{
			i = 0;
			do
			{
				z[i] = c;
				i++;
				c = getchar();
			} while (c >= '0'&&c <= '9');
			z[i] = 0;
			d = atoi(z); /* 将字符串数组转为整型存于d */
			Push(&OPND, d);
		}
		else /* c是非法字符 */
		{
			printf("ERROR3\n");
			exit(ERROR);
		}
		GetTop(OPTR, &x);
	}
	GetTop(OPND, &x);
	return x;
}

void main() /* 有改动 */
{
	printf("请输入算术表达式,负数要用(0-正数)表示,并以=结束\n");
	printf("%d\n", EvaluateExpression());
}

运行结果:

发布了135 篇原创文章 · 获赞 64 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/qq_42185999/article/details/104991636