(轉載)棧的一個應用 ---中綴表達式轉化爲後綴表達式

 

理論:

表達式的表示形式有中綴、前綴和後綴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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章