`

(转载)栈的一个应用 ---中缀表达式转化为后缀表达式

 
阅读更多

 

理论:

表达式的表示形式有中缀、前缀和后缀3中形式。中缀表达式按操作符的优先级进行计算(后面代码实现只包括+-*\,小括号),即数学运算。后缀表达式中只有操作数和操作。操作符在两个操作数之后。它的计算规则非常简单,严格按照从左到右的次序依次执行每一个操作。每遇到一个操作符,就将前面的两个数执行相应的操作。

 

由后缀表达式计算中缀表达式原理:计算机处理后缀表达式求值问题是比较方便的,即将遇到的操作数暂存于一个操作数栈中,凡是遇到操作数,便从栈中pop出两个操作数,并将结果存于操作数栈中,直到对后缀表达式中最后一个操作数处理完,最后压入栈中的数就是后最表达式的计算结果。

 

 

中缀表达式转换为等价的后缀表达式

中缀表达式不方便与计算机处理,通常要讲中缀表达式转换为一个与之等价的后缀表达式。等价是指两个表达式的计算顺序和计算结果完全相同。

中缀表达式:0.3/(5*2+1)#

的等价后缀表达式是:0.3 5 2 * 1 + /#

仔细观察这两个等价的表达式可知,操作数的出现次序是相同的,但运算符的出现次序是不同的。在后缀表达式中,运算符的出现次序是实际进行操作的次序;在中追表达式中,由于受到操作符的优先级和括号的影响,操作符出现次序与实际进行操作的次序很可能是不一样的。

算法描述:

将中缀表达式转换为等价的后缀表达式的过程要使用一个栈放“(”,具体可以按照下面的方式进行。

(1)从左到右一次扫描中缀表达式的每一个字符,如果是数字字符和圆点“.”则直接将它们写入后缀表达式中。

(2)如果遇到的是开括号“(”,则将它们压入一个操作符栈(不需要与栈顶操作符相比较),它表明一个新的计算层次的开始,在遇到和它匹配的闭括号“)”时,将栈中的元素弹出来并放入后缀表达式中,直到栈顶元素为“(”时,将栈顶元素“(”弹出(不需要加入后缀表达式),表明这一层括号内的操作处理完毕。

(3)如果遇到的是操作符,则将该操作符和操作符栈顶元素比较:

                1、当所遇到的操作符的优先级小于或等于栈顶元素的优先级时,则取出栈顶元素放入后缀表式, 

                      并弹出该栈顶元素,反复执行直到栈顶元素的优先级小于当前操作符的优先级;

                2、当所遇到的操作符的优先级大于栈顶元素的优先级的时则将它压入栈中。

   (4)重复上述步骤直到遇到中缀表达式的结束符标记“#”,弹出栈中的所有元素并放入后缀表达式中,转换结束。

C++ 代码描述算法:

(可以识别小数点,括号,实现加减乘除四则运算,可以处理任意长度的操作数,包括小数)

 

//MyStack.h

#include <iostream>
using namespace std;

template <class ElemType> class MyStack
{
public:
	const static  int MAXSIZE =100;
	ElemType data[MAXSIZE];
	int top;

public:
	void init();			// 初始化栈
	bool empty();			// 判断栈是否为空
	ElemType gettop();	    // 读取栈顶元素(不出栈)
	void push(ElemType x);	// 进栈
	ElemType pop();			// 出栈
};


template<class T> void MyStack<T>::init()
{
	this->top = 0;
}

template<class T> bool MyStack<T>::empty()
{
	return this->top == 0? true : false;
}

template<class T> T MyStack<T>::gettop()
{
	if(empty())
	{
		cout << "栈为空!\n";
		exit(1);
	}
	return this->data[this->top-1];
}

template<class T> void MyStack<T>::push(T x)
{
	if(this->top == MAXSIZE)
	{
		cout << "栈已满!\n";
		exit(1);
	}
	this->data[this->top] =x;
	this->top ++;
}

template<class T> T MyStack<T>::pop()
{
	if(this->empty())
	{
		cout << "栈为空! \n";
		exit(1);
	}

	T e =this->data[this->top-1];
	this->top --;
	return e;
}
 

 

 

// PrefixToPostfix.h

#include <vector>
using namespace std;

bool isoperator(char op);						  // 判断是否为运算符
int priority(char op);						  	  // 求运算符优先级
void postfix(char pre[] , char post[],int &n);    // 把中缀表达式转换为后缀表达式
double read_number(char str[],int *i);			  // 将数字字符串转变成相应的数字
double postfix_value(char post[]);				  // 由后缀表达式字符串计算相应的中值表达式的值	

 

 

 

 

// PrefixToPostfix.cpp

#include "MyStack.h"
#include "PrefixToPostfix.h"

#include <iostream>
using namespace std;

void main()
{
	MyStack<int> stack ;
	stack.init();

	//char pre[] ="22/(5*2+1)#";
	char exp[100];
	cout << "输入表达式(中缀,以#结束):";
	cin >> exp;

	char post[100] ;
	//cout <<"中缀表达式为:"<< pre << endl;

	int n =0;			// 返回后缀表达式的长度
	postfix(exp,post,n);
	cout <<"后缀表达式为:";
	for( int i =0 ;i < n ;i++)
		cout << post[i] ;

	cout << "\n由后缀表达式计算出的数值结果:  ";
	cout << postfix_value(post) << endl;

	system("pause");
}

bool isoperator(char op)
{
	switch(op)
	{
	case '+':
	case '-':
	case '*':
	case '/':
		return 1;
	default : 
		return 0;
	}
}


int priority(char op)
{
	switch(op)
	{
	case '#':
		return -1;
	case '(':
		return 0;
	case '+':
	case '-':
		return 1;
	case '*':
	case '/':
		return 2;
	default :
		return -1;
	}
}

//	 把中缀表达式转换为后缀表达式,返回后缀表达式的长度(包括空格)
void postfix(char pre[] ,char post[],int &n)
{
	int i = 0 ,j=0;
	MyStack<char> stack;
	stack.init();		// 初始化存储操作符的栈

	stack.push('#');	// 首先把结束标志‘#’放入栈底

	while(pre[i]!='#')
	{
		if((pre[i]>='0' && pre[i] <='9')||pre[i] =='.') // 遇到数字和小数点直接写入后缀表达式
		{
			post[j++] = pre[i];
			n++;
		}
		else if (pre[i]=='(')	// 遇到“(”不用比较直接入栈
			stack.push(pre[i]);
		else if(pre[i] ==')')  // 遇到右括号将其对应左括号后的操作符(操作符栈中的)全部写入后缀表达式
		{
			while(stack.gettop()!='(')
			{
				post[j++] = stack.pop();
				n++;
			}
			stack.pop(); // 将“(”出栈,后缀表达式中不含小括号
		}
		else if (isoperator(pre[i]))
		{
			post[j++] = ' '; // 用空格分开操作数(
			n++;
			while(priority(pre[i]) <= priority(stack.gettop())) 
			{
				// 当前的操作符小于等于栈顶操作符的优先级时,将栈顶操作符写入到后缀表达式,重复此过程
				post[j++] = stack.pop();
				n++;
			}

			stack.push(pre[i]);	// 当前操作符优先级大于栈顶操作符的优先级,将该操作符入栈
		}

		i++;
	}
	while(stack.top) // 将所有的操作符加入后缀表达式
	{
		post[j++] = stack.pop();
		n++;
	}
}

double read_number(char str[],int *i)
{
	double x=0.0;
	int k = 0;
	while(str[*i] >='0' && str[*i]<='9')  // 处理整数部分
	{
		x = x*10+(str[*i]-'0');
		(*i)++;
	}

	if(str[*i]=='.') // 处理小数部分
	{
		(*i)++;
		while(str[*i] >= '0'&&str[*i] <='9')
		{
			x = x * 10 + (str[*i]-'0');
			(*i)++;
			k++;
		}
	}
	while(k!=0)
	{
		x /= 10.0;
		k--;
	}

	return x;
}

double postfix_value(char post[])
{
	MyStack<double> stack;	// 操作数栈
	stack.init();

	int i=0 ;
	double x1,x2;

	while(post[i] !='#')
	{
		if(post[i] >='0' && post[i] <='9')
			stack.push(read_number(post,&i));
		else if(post[i] == ' ')
			i++;
		else if (post[i] =='+')
		{
			x2 = stack.pop();
			x1 = stack.pop();
			stack.push(x1+x2);
			i++;
		}
		else if (post[i] =='-')
		{
			x2 = stack.pop();
			x1 = stack.pop();
			stack.push(x1-x2);
			i++;
		}
		else if (post[i] =='*')
		{
			x2 = stack.pop();
			x1 = stack.pop();
			stack.push(x1*x2);
			i++;
		}
		else if (post[i] =='/')
		{
			x2 = stack.pop();
			x1 = stack.pop();
			stack.push(x1/x2);
			i++;
		}
	}
	return stack.gettop();
}
 

 

运行结果:

 转自:http://apps.hi.baidu.com/share/detail/21591676

完整代码见博文:http://blog.csdn.net/swkiller/article/details/6829386

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics