1. 程式人生 > >棧實現表示式求值(C++)

棧實現表示式求值(C++)

為了實現用棧計算算數表示式的值,需設定兩個工作棧:用於儲存運算子的棧opter,以及用於儲存運算元及中間結果的棧opval。

演算法基本思想如下:

(1)首先將運算元棧opval設為空棧,而將'#'作為運算子棧opter的棧底元素,這樣的目的是判斷表示式是否求值完畢。

(2)依次讀入表示式的每個字元,表示式須以'#'結尾,若是運算元則入棧opval,若是運算子,則將此運算子c與opter的棧頂元素top比較優先順序後執行相應的操作,(具體操作如下:(i)若top的優先順序小於c,即top<c,則將c直接入棧opter,並讀入下一字元賦值給c;(ii)若top的優先順序等於c,即top=c,則彈出opter的棧頂元素,並讀入下一字元賦值給c,這一步目的是進行括號操作;(iii)若top優先順序高於c,即top>c,則表明可以計算,此時彈出opval的棧頂兩個元素,並且彈出opter棧頂的的運算子,計算後將結果放入佔opval中。)直至opter的棧頂元素和當前讀入的字元均為'#',此時求值結束。

算符間的優先關係如下表所示:


表中需要注意的是θ1為opter的棧頂元素,θ2位從表示式中讀取的操作符,此優先順序表可以用二維陣列實現,具體見程式碼(表來源:嚴蔚敏《資料結構》)。

具體程式碼如下:

[cpp] view plain copy print?
  1. #include<iostream>     //輸入的表示式要以'#'結尾,如‘5+6*3/(3-1)#’
  2. #include<cstring>
  3. #include<cstdio>
  4. #include<cctype>
  5. #include<stack>
  6. usingnamespace std;  
  7. stack<char
    > opter;    //運算子棧
  8. stack<double> opval;  //運算元棧
  9. int getIndex(char theta)   //獲取theta所對應的索引
  10. {  
  11.     int index = 0;  
  12.     switch (theta)  
  13.     {  
  14.     case'+':  
  15.         index = 0;  
  16.         break;  
  17.     case'-':  
  18.         index = 1;  
  19.         break;  
  20.     case'*':  
  21.         index = 2;  
  22.         break;  
  23.     case'/':  
  24.         index = 3;  
  25.         break;  
  26.     case'(':  
  27.         index = 4;  
  28.         break;  
  29.     case')':  
  30.         index = 5;  
  31.         break;  
  32.     case'#':  
  33.         index = 6;  
  34.     default:break;  
  35.     }  
  36.     return index;  
  37. }  
  38. char getPriority(char theta1, char theta2)   //獲取theta1與theta2之間的優先順序
  39. {  
  40.     constchar priority[][7] =     //算符間的優先順序關係
  41.     {  
  42.         { '>','>','<','<','<','>','>' },  
  43.         { '>','>','<','<','<','>','>' },  
  44.         { '>','>','>','>','<','>','>' },  
  45.         { '>','>','>','>','<','>','>' },  
  46.         { '<','<','<','<','<','=','0' },  
  47.         { '>','>','>','>','0','>','>' },  
  48.         { '<','<','<','<','<','0','=' },  
  49.     };  
  50.     int index1 = getIndex(theta1);  
  51.     int index2 = getIndex(theta2);  
  52.     return priority[index1][index2];  
  53. }  
  54. double calculate(double b, char theta, double a)   //計算b theta a
  55. {  
  56.     switch (theta)  
  57.     {  
  58.     case'+':  
  59.         return b + a;  
  60.     case'-':  
  61.         return b - a;  
  62.     case'*':  
  63.         return b * a;  
  64.     case'/':  
  65.         return b / a;  
  66.     default:  
  67.         break;  
  68.     }  
  69. }  
  70. double getAnswer()   //表示式求值
  71. {  
  72.     opter.push('#');      //首先將'#'入棧opter
  73.     int counter = 0;      //新增變數counter表示有多少個數字相繼入棧,實現多位數的四則運算
  74.     char c = getchar();  
  75.     while (c != '#' || opter.top() != '#')   //終止條件
  76.     {  
  77.         if (isdigit(c))   //如果c在'0'~'9'之間
  78.         {  
  79.             if (counter == 1)   //counter==1表示上一字元也是數字,所以要合併,比如12*12,要算12,而不是單獨的1和2
  80.             {  
  81.                 double t = opval.top();  
  82.                 opval.pop();  
  83.                 opval.push(t * 10 + (c - '0'));  
  84.                 counter = 1;  
  85.             }  
  86.             else
  87.             {  
  88.                 opval.push(c - '0');     //將c對應的數值入棧opval
  89.                 counter++;  
  90.             }  
  91.             c = getchar();  
  92.         }  
  93.         else
  94.         {  
  95.             counter = 0;   //counter置零
  96.             switch (getPriority(opter.top(), c))   //獲取運算子棧opter棧頂元素與c之間的優先順序,用'>','<','='表示
  97.             {  
  98.             case'<':               //<則將c入棧opter
  99.                 opter.push(c);  
  100.                 c = getchar();  
  101.                 break;  
  102.             case'=':               //=將opter棧頂元素彈出,用於括號的處理
  103.                 opter.pop();  
  104.                 c = getchar();  
  105.                 break;  
  106.             case'>':               //>則計算
  107.                 char theta = opter.top();  
  108.                 opter.pop();  
  109.                 double a = opval.top();  
  110.                 opval.pop();  
  111.                 double b = opval.top();  
  112.                 opval.pop();  
  113.                 opval.push(calculate(b, theta, a));  
  114.             }  
  115.         }  
  116.     }  
  117.     return opval.top();   //返回opval棧頂元素的值
  118. }  
  119. int main()  
  120. {  
  121.     //freopen("test.txt", "r", stdin);
  122.     int t;     // 需要計算的表示式的個數
  123.     cin >> t;  
  124.     getchar();  
  125.     while (t--)  
  126.     {  
  127.         while (!opter.empty())opter.pop();  
  128.         while (!opval.empty())opval.pop();  
  129.         double ans = getAnswer();  
  130.         cout << ans << endl<< endl;  
  131.         getchar();  
  132.     }  
  133.     return 0;  
  134. }  
#include<iostream>     //輸入的表示式要以'#'結尾,如‘5+6*3/(3-1)#’
#include<cstring>
#include<cstdio>
#include<cctype>
#include<stack>
using namespace std;

stack<char> opter;    //運算子棧
stack<double> opval;  //運算元棧

int getIndex(char theta)   //獲取theta所對應的索引
{
	int index = 0;
	switch (theta)
	{
	case '+':
		index = 0;
		break;
	case '-':
		index = 1;
		break;
	case '*':
		index = 2;
		break;
	case '/':
		index = 3;
		break;
	case '(':
		index = 4;
		break;
	case ')':
		index = 5;
		break;
	case '#':
		index = 6;
	default:break;
	}
	return index;
}

char getPriority(char theta1, char theta2)   //獲取theta1與theta2之間的優先順序
{
	const char priority[][7] =     //算符間的優先順序關係
	{
		{ '>','>','<','<','<','>','>' },
		{ '>','>','<','<','<','>','>' },
		{ '>','>','>','>','<','>','>' },
		{ '>','>','>','>','<','>','>' },
		{ '<','<','<','<','<','=','0' },
		{ '>','>','>','>','0','>','>' },
		{ '<','<','<','<','<','0','=' },
	};

	int index1 = getIndex(theta1);
	int index2 = getIndex(theta2);
	return priority[index1][index2];
}

double calculate(double b, char theta, double a)   //計算b theta a
{
	switch (theta)
	{
	case '+':
		return b + a;
	case '-':
		return b - a;
	case '*':
		return b * a;
	case '/':
		return b / a;
	default:
		break;
	}
}

double getAnswer()   //表示式求值
{
	opter.push('#');      //首先將'#'入棧opter
	int counter = 0;      //新增變數counter表示有多少個數字相繼入棧,實現多位數的四則運算
	char c = getchar();
	while (c != '#' || opter.top() != '#')   //終止條件
	{
		if (isdigit(c))   //如果c在'0'~'9'之間
		{
			if (counter == 1)   //counter==1表示上一字元也是數字,所以要合併,比如12*12,要算12,而不是單獨的1和2
			{
				double t = opval.top();
				opval.pop();
				opval.push(t * 10 + (c - '0'));
				counter = 1;
			}
			else
			{
				opval.push(c - '0');     //將c對應的數值入棧opval
				counter++;
			}
			c = getchar();
		}
		else
		{
			counter = 0;   //counter置零
			switch (getPriority(opter.top(), c))   //獲取運算子棧opter棧頂元素與c之間的優先順序,用'>','<','='表示
			{
			case '<':               //<則將c入棧opter
				opter.push(c);
				c = getchar();
				break;
			case '=':               //=將opter棧頂元素彈出,用於括號的處理
				opter.pop();
				c = getchar();
				break;
			case '>':               //>則計算
				char theta = opter.top();
				opter.pop();
				double a = opval.top();
				opval.pop();
				double b = opval.top();
				opval.pop();
				opval.push(calculate(b, theta, a));
			}
		}
	}
	return opval.top();   //返回opval棧頂元素的值
}

int main()
{
	//freopen("test.txt", "r", stdin);
	int t;     // 需要計算的表示式的個數
	cin >> t;
	getchar();
	while (t--)
	{
		while (!opter.empty())opter.pop();
		while (!opval.empty())opval.pop();
		double ans = getAnswer();
		cout << ans << endl<< endl;
		getchar();
	}
	return 0;
}

結果: