前綴中綴后綴表達式


 

快要開始工作了,人生的第一份工作要格外重視,畢竟要有一個好的開始嘛。所以抽幾天時間復習一下數據結構。看到堆棧部分,有一個運用堆棧的列子,表達式的中綴和前綴后綴的轉換,剛開始找工作面試和筆試都遇到了這樣的問題,以前模模糊糊的,現在搞明白了

一.表達式的三種形式:

中綴表達式:運算符放在兩個運算對象中間,這是我們書寫的時候最熟悉的一種形式,如:(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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM