中綴表達式轉後綴表達式算法及實現—棧的應用

我們在數學中常見的計算式,例如2+(3*4)叫做中綴表達式。表達式中涉及到了多個運算符,而運算符之間是有優先級的。計算機在計算並且處理這種表達式時,需要將中綴表達式轉換成後綴表達式,然後再進行計算。

中綴表達式:0.3/(5*2+1) 的等價後綴表達式是:0.3 5 2 * 1 + /

        中綴表達式轉後綴表達式遵循以下原則:

        1.遇到操作數,直接輸出;

        2.棧爲空時,遇到運算符,入棧;

        3.遇到左括號,將其入棧;

        4.遇到右括號,執行出棧操作,並將出棧的元素輸出,直到彈出棧的是左括號,左括號不輸出;

        5.遇到其他運算符'+''-''*''/'時,彈出所有優先級大於或等於該運算符的棧頂元素,然後將該運算符入棧;

        6.最終將棧中的元素依次出棧,輸出。

        經過上面的步驟,得到的輸出既是轉換得到的後綴表達式。

        舉例:a+b*c+(d*e+f)*g    ---------> abc*+de*f+g*+

遇到a,直接輸出:

遇到+,此時棧爲空,入棧:

遇到b,直接輸出:

遇到*,優先級大於棧頂符號優先級,入棧:

遇到c,輸出:

遇到+,目前站內的*與+優先級都大於或等於它,因此將棧內的*,+依次彈出並且輸出,並且將遇到的這個+入棧:

遇到(,將其入棧:

遇到d,直接輸出:

遇到*,由於*的優先級高於處在棧中的(,因此*入棧:

遇到e,直接輸出:

遇到+,棧頂的*優先級高於+,但是棧內的(低於+,將*出棧輸出,+入棧:

遇到f,直接輸出:

遇到),彈出棧頂元素並且輸出,直到彈出(才結束,在這裏也就是彈出+輸出,彈出(不輸出:

遇到*,優先級高於棧頂+,將*入棧:

遇到g,直接輸出:

此時已經沒有新的字符了,依次出棧並輸出操作直到棧爲空:

明白了這個過程,現在就需要用代碼實現了。對於各種運算符的優先級,可以使用整數來表示運算符的級別。可以定義一個函數來返回各種符號的優先級數字。

//MyStack.h

#include <iostream>
using namespace std;

const static  int MAXSIZE =100;

template <class ElemType> class MyStack
{
public:
	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();
}

小注:

error C2258: illegal pure syntax, must be '= 0'

在VC 6.0中這樣的錯誤一般是因爲定義常量不正確導致的,在類中不能直接給變量賦值,也不能在類中定義一個const量,如:
class MyStack
{
public:

        ……   

const static int MAXSIZE =100;


}

這樣就會出錯,所以必須把上面寫成下面格式,

const static int MAXSIZE =100;

class MyStack
{
public:
        ……
}
這樣錯誤就會避免~

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