前缀中缀后缀表达式

 

快要开始工作了,人生的第一份工作要格外重视,毕竟要有一个好的开始嘛。所以抽几天时间复习一下数据结构。看到堆栈部分,有一个运用堆栈的列子,表达式的中缀和前缀后缀的转换,刚开始找工作面试和笔试都遇到了这样的问题,以前模模糊糊的,现在搞明白了

一.表达式的三种形式:

中缀表达式:运算符放在两个运算对象中间,这是我们书写的时候最熟悉的一种形式,如:(2+1)*3

后缀表达式:不包含括号,运算符放在两个运算对象的后面,所有的计算按运算符出现的顺序,严格从左向右进行(不再考虑运算符的优先规则,如:2 1 + 3 *

前缀表达式:同后缀表达式一样,不包含括号,运算符放在两个运算对象的前面,如:* + 2 1 3

二.中缀表达式向后缀和前缀表达式的转换

转化的过程需要一个辅助的运算符堆栈op。并且要预先给运算符设置好运算的优先级如下所示:

struct
{
	char ch;
	int pri;
}
lpri[]={{'=',0},{'(',1},{'*',5},{'/',5},{'+',3},{'-',3},{')',6}},
rpri[]={{'=',0},{'(',6},{'*',4},{'/',4},{'+',2},{'-',2},{')',1}};

  我们可以看到同一个运算符作为左(对应lpri数组)、右(对应rlpri数组)运算符时他们的优先级不同,这是为了实现表达式求值时"从左到右计算"的规定设计的。为了方便算法的实现,在op堆栈的栈地存放的是'='作为终结。

将算术表达式exp转换成后缀表达式postexp的过程如下:

 

初始化运算符堆栈op;

将'='进栈;

从exp读取字符ch;

while(ch!='\0')
{
     if(ch不是运算符)
          将后续的所有数字均依次存放到postexp中,并以字符'#'标志数值串的结束;
   else
           switch(precede(op的栈顶运算符,ch))
           {
             case '<':     //栈顶运算符优先级低
               将ch进栈;
               从exp读取下一个字符ch;
               break;
         case '=':
                       退栈;
               从exp读取下一个字符ch;
               break;
         case '>':
                      退栈运算符并将其存放到postexp中;
               break;
         }
}

若字符串exp扫描完毕,则将运算符栈op中'='之前的所有运算符依次出栈并存放到
postexp中。最后得到后缀表达式postexp。

 具体的C语言代码如下:

#include "stdafx.h"
#include <iostream>

#define MaxOp 10
#define MaxSize 50

struct
{
	char ch;
	int pri;
}
lpri[]={{'=',0},{'(',1},{'*',5},{'/',5},{'+',3},{'-',3},{')',6}},
rpri[]={{'=',0},{'(',6},{'*',4},{'/',4},{'+',2},{'-',2},{')',1}};

int leftpri(char op)
{
	int i;
	for(i=0;i<MaxOp;i++)
		if(lpri[i].ch==op) return lpri[i].pri;
}

int rightpri(char op)
{
	int i;
	for(i=0;i<MaxOp;i++)
		if(rpri[i].ch==op) return rpri[i].pri;
}



int isOp(char ch)
{
	if(ch=='('||ch==')'||ch=='*'||ch=='/'||ch=='+'||ch=='-')
		return 1;
	else
		return 0;
}

int precede(char op1,char op2)
{
	if(leftpri(op1)==rightpri(op2))
		return 0;
	else
		if(leftpri(op1)<rightpri(op2))
			return -1;
		else
			return 1;
}

int precedeT(char op1,char op2)
{
	if(leftpri(op1)==rightpri(op2))
		return 0;
	else
		if(leftpri(op1)<rightpri(op2))
			return 1;
		else
			return -1;
}



void trans(char *exp,char postexp[])
{
	
	typedef struct
	{
		char data[MaxSize];
		int top;
	}OP;

	OP *op=(OP *)malloc(sizeof(OP));
	int i=0;
	op->top=-1;
	op->top++;
	op->data[op->top]='=';


	while(*exp!='\0')
	{
		if(!isOp(*exp))
		{
			while(*exp>='0'&&*exp<='9')
			{
				postexp[i++]=*exp;
				exp++;
			}
			postexp[i++]='#';
		}else
			switch(precede(op->data[op->top],*exp))
		{
			case -1:
				op->data[++op->top]=*exp;
				exp++;
				break;
			case 0:
				op->top--;
				exp++;
				break;
			case 1:
				postexp[i++]=op->data[op->top--];
				break;
		}
	}
	while(op->data[op->top]!='=')
	{
		postexp[i++]=op->data[op->top--];
	}
	postexp[i]='\0';
	
}

void transT(char *exp,char postexp[])
{
	
	typedef struct
	{
		char data[MaxSize];
		int top;
	}OP;

	OP *op=(OP *)malloc(sizeof(OP));
	int i=0;
	op->top=-1;
	op->top++;
	op->data[op->top]='=';
	int j=-1;
	char *p=exp;
	while(*p!='\0')
	{
		p++;
		j++;
	}

	while(j>-1)
	{
		if(!isOp(exp[j]))
		{
			while(exp[j]>='0'&&exp[j]<='9')
			{
				postexp[i++]=exp[j];
				j--;
			}
			postexp[i++]='#';
		}else
			switch(precedeT(exp[j],op->data[op->top]))
		{
			case -1:
				op->data[++op->top]=exp[j];
				j--;
				break;
			case 0:
				op->top--;
				j--;
				break;
			case 1:
				postexp[i++]=op->data[op->top--];
				break;
		}
	}
	while(op->data[op->top]!='=')
	{
		postexp[i++]=op->data[op->top--];
	}
	postexp[i]='\0';
	
}

float compvalue(char *postexp)
{
	typedef struct
	{
		float data[MaxSize];
		int top;
	}OP;

	float a,b,c,d;
	OP *st = (OP *)malloc(sizeof(OP));
	st->top=-1;
	while(*postexp!='\0')
	{
		switch(*postexp)
		{
		case '+':
			a=st->data[st->top--];
			b=st->data[st->top--];
			c=a+b;
			st->data[++st->top]=c;
			break;
		case '-':
			a=st->data[st->top--];
			b=st->data[st->top--];
			c=b-a;
			st->data[++st->top]=c;
			break;
		case '*':
			a=st->data[st->top--];
			b=st->data[st->top--];
			c=b*a;
			st->data[++st->top]=c;
			break;
		case '/':
			a=st->data[st->top--];
			b=st->data[st->top--];
			if(a!=0)
			{
				c=b/a;
				st->data[++st->top]=c;
			}
			else
			{
				printf("\0除零错误!\n");
				exit(0);
			}
			break;
		default:
			d=0;
			while(*postexp>='0'&&*postexp<='9')
			{
				d=10*d + *postexp - '0';
				postexp++;
			}
			st->data[++st->top]=d;
			break;
		}
		postexp++;
	}
	return st->data[st->top];
}

float compvalueT(char *postexp)
{
	typedef struct
	{
		float data[MaxSize];
		int top;
	}OP;

	float a,b,c,d;
	OP *st = (OP *)malloc(sizeof(OP));
	st->top=-1;
	while(*postexp!='\0')
	{
		switch(*postexp)
		{
		case '+':
			a=st->data[st->top--];
			b=st->data[st->top--];
			c=a+b;
			st->data[++st->top]=c;
			break;
		case '-':
			a=st->data[st->top--];
			b=st->data[st->top--];
			c=a-b;
			st->data[++st->top]=c;
			break;
		case '*':
			a=st->data[st->top--];
			b=st->data[st->top--];
			c=a*b;
			st->data[++st->top]=c;
			break;
		case '/':
			a=st->data[st->top--];
			b=st->data[st->top--];
			if(b!=0)
			{
				c=a/b;
				st->data[++st->top]=c;
			}
			else
			{
				printf("\0除零错误!\n");
				exit(0);
			}
			break;
		default:
			d=0;
			while(*postexp>='0'&&*postexp<='9')
			{
				d=10*d + *postexp - '0';
				postexp++;
			}
			st->data[++st->top]=d;
			break;
		}
		postexp++;
	}
	return st->data[st->top];
}

int _tmain(int argc, _TCHAR* argv[])
{

	char exp[]="1+((2+3)*4)-5";
	//char expT[]="1+((2+3)*4)-5";
	
	
	
	//fanzhuan(exp,expT);
	//printf("expT:%s\n",expT);

	char postexp[MaxSize];
	char postexpT[MaxSize];
	trans(exp,postexp);
	

	printf("中缀表达式:%s\n",exp);
	printf("后缀表达式:%s\n",postexp);
	transT(exp,postexpT);
	printf("前缀表达式:%s\n",postexpT);
	printf("后缀表达式的值:%f\n",compvalue(postexp));
	printf("前缀表达式的值:%f\n",compvalueT(postexpT));

	return 0;
}

哈哈,上面的代码已经包括中缀转前后缀和前后缀的求值算法实现了。

前缀和后缀表达式转换方法的区别主要在,后缀是从左往右扫描exp,前缀反之。所以两者的左右运算符的划分是相反的。这一点还体现在求值的时候。

好吧,弄好一篇了    2012-07-12

原文地址:https://www.cnblogs.com/woainilsr/p/2587304.html