表达式求值(顺序栈实现)

问题:算数运算的表达式求知


这道题不难,但是当你认真去编代码的时候,还是要考虑好多细节。


算法原理如下:

我们都知道算术四则运算的运算规则是:

先乘除,后加减。

从左到右计算

先算括号内,再算括号外


表达式组成

任何一个表达式都有操作数、运算符和界定符组成。

操作数即可以是常量,也可以是被说明为变量或常量的标识符。

运算符可以分为算术运算,关系运算和逻辑运算符。

界定符有左右括号和结束符等。

本文为了方便演示只使用算术运算。


运算符优先级

对于连个相继出现的操作符θ1和θ有三种关系:大于、等于和小于。由此可以列出“+-*/”之间的优先级。如下表:


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

 

加减乘除优先性都低于“(”但是高于“)”,由运算从左到右可知,当θ12 ,令θ12

为了算法简洁,在表达式的左边和右边虚设一个“#”,这一对“#”表示一个表达式求值完成。


“(”=“)”当一对括号相遇时表示括号内已运算完成。

“)”和“(”、“#”和“(”、“(”和“#”无法相继出现如果出现则表达式出现语法错误。


为实现优先算法,可以使用两个工作栈,一个是OPTR,用于寄存运算符,一个是OPND,用于寄存运算数和运算结果。

代码如下:(存在一个bug)

#include<stdio.h>   //表达式求值,顺序栈 
#include<stdlib.h>
#define STACK_INIT_SIZE 100
#define STACKINCREMENT 10
#define OK 1
#define ERROR 0

typedef int Status;

typedef struct{
	char * base;
	char * top;
	int stacksize; 
}SqStack;

//函数声明..................................
Status InitStack(SqStack &S);       //符号栈的建立 

Status Push(SqStack &S,char e);     //入栈 

void OperandType_EvaluateExpression(SqStack &OPND,SqStack &OPTR);

char GetTop(SqStack S);      //返回栈顶元素 

Status Pop(SqStack &S,char &e);     //出栈 

Status IsDigit(char c);   //判断是否为数字 

char Precede(char a,char e);     //符号优先级判断, 

int swap_char_to_int(char a);     //在Precede中的字符转换为数字函数 

char Operate(char a,char x,char b);   //运算函数,返回为char型的数字 

Status shownumbers(SqStack S);

//函数实现........................................... 

Status InitStack(SqStack &S)
{
	S.base = (char *)malloc(STACK_INIT_SIZE * sizeof(char));
	if(!S.base)
		exit(ERROR);
	S.top = S.base;
	S.stacksize = STACK_INIT_SIZE;
	
	return OK;
}


Status Push(SqStack &S,char e)
{
	if(S.top - S.base >= S.stacksize)
	{
		S.base = (char *)realloc(S.base,(S.stacksize + STACKINCREMENT) * sizeof(char));
		if(!S.base)
			exit(ERROR);
		S.top = S.base + S.stacksize;
		S.stacksize += STACKINCREMENT;
	}
	*S.top = e;
	S.top++;
	return OK;
}

void OperandType_EvaluateExpression(SqStack &OPND,SqStack &OPTR)
{
	char c;
	char x;
	char b;
	char a;
	Push(OPTR,'#');
	c = getchar();
	while(c != '#' || GetTop(OPTR) != '#')
	{
		if(IsDigit(c))    //若是数字则进数字栈,不是判断符号优先级 
		{
			Push(OPND,c);
			c = getchar();
		}
		else
		{
			switch(Precede(GetTop(OPTR),c))
			{
				case '<':
					Push(OPTR,c);
					c = getchar();
					break;
				case '=':
					Pop(OPTR,x);
					c = getchar();
					break;
				case '>':
					Pop(OPTR,x);
					Pop(OPND,b);
					Pop(OPND,a);
					Push(OPND,Operate(a,x,b));
					break;
			//	printf("") 
				
			}
		} 
		
	}
/*	char sum;
	sum = GetTop(OPND);
	printf("%c\n",sum);
	shownumbers(OPND);
	printf("\n");
	shownumbers(OPTR);  */
	
}


char GetTop(SqStack S)
{
	char e;
	
	if(S.top == S.base)
		exit(-1);
	else
		e = *(S.top-1);
	return e;
}

Status Pop(SqStack &S, char &e)
{
	if(S.base == S.top)
		return ERROR;
	else
		e = *--S.top;
	return OK; 
 } 
 

Status IsDigit(char c)
{
	if(c >= '0' && c <= '9')
		return 1;
	else
		return 0;
}

char Precede(char a,char e)
{
	int i,j;
	int flag;
	int symbol[7][7] = {
		{0,0,1,1,1,0,0},
		{0,0,1,1,1,0,0},
		{0,0,0,0,1,0,0},
		{0,0,0,0,1,0,0},
		{1,1,1,1,1,2,4},
		{0,0,0,0,4,0,0},
		{1,1,1,1,1,4,2},
		}; 
	i  = swap_char_to_int(a);
	j = swap_char_to_int(e);
	flag = symbol[i][j];
	
	switch(flag)
	{
		case 0:return '>';
		case 1:return '<';
		case 2:return '=';
		case 4:exit(-1);
	}
	
	
	
} 

int swap_char_to_int(char a)
{
	switch(a)
	{
		case '+':return 0;
		case '-':return 1;
		case '*':return 2;
		case '/':return 3;
		case '(':return 4;
		case ')':return 5;
		case '#':return 6;
	}
} 


char Operate(char a,char x,char b)
{
	int c,d;
	int sum;
	c = a-'0';
	d = b-'0';
	
	switch(x)
	{
		case '+':sum = c+d;break;
		case '-':sum = c-d;break;
		case '*':sum = c*d;break;
		case '/':sum = c/d;break;
	}
	
	return sum+'0';
} 

Status shownumbers(SqStack S)
{
	int numbers = 1;
	if(S.top == S.base)
	{
		printf("栈为空栈,无法打印\n");
		exit(-1);
	}
	while(S.base < S.top)
	{
		S.top--;
		printf("%c ",*S.top);
		numbers++;
	}

	
}

//驱动函数..................
int main()
{
	int sum;
	
	SqStack OPTR;    //符号栈 
	SqStack OPND;    //数字栈
	
	InitStack(OPTR);
	InitStack(OPND);
	OperandType_EvaluateExpression(OPND,OPTR);
	
	sum = GetTop(OPND) - '0';
	printf("%d",sum);     
	
	return 0;
	
 } 



运行结果如下:

1*2+6/2*(2+3*5)#

53
--------------------------------
Process exited after 16.61 seconds with return value 0

请按任意键继续. . .


存在BUG如下:

1,输入的整数必须小于10.

2,不能输入小数,除数必须大于被除数。


分析:

1.代码中由于通过getchar()读取,所以当输入10/5的时候,读取的其实是1 和 0 两个字符。

2.这个是因为int型的除法问题,比如当3/7的时候,并不是小数,而是得0。


对于的一个bug,我想到的是,可以在输入的时候,建立数组完成,但是这个会导致输入有限,或者继续用getchar()输入,输入后进行数字的判断来解决,想一想是可以实现的。如果是连续的数字,就累加,终止条件是下一个符号。


对于第二个bug,则是要建立float型的数据类型,把char型转换为float型,但是或许又潜在的问题?并没有尝试。

猜你喜欢

转载自blog.csdn.net/rage_/article/details/64214863