天天看點

面向對象程式設計第四次作業

Github位址:點這裡

主要内容:

  • 用棧對表達式進行處理 C++ STL--stack/queue 的使用方法
  • 對表達式進行計算(優先級及負數問題)

具體實作

本來自己沒有絲毫頭緒,在看過其他已經完成的同學的部落格之後才了解到可以通過将中綴表達式變形為字首表達式的方式友善計算機計算。于是百度,找到了用棧轉換表達式形式以及計算的教程,于是接下來的工作就是按部就班,照着教程一步一步寫,慢慢debug。其中碰到的負數問題也因為看過廖興桔同學的部落格而迎刃而解。

代碼

#include<string>
#include<queue>
#include<cctype>
#include<stack>
#include<sstream>
#include"Calculator.h"

using namespace std;

int Calculation::priority(char x)//比較優先級
{
	if (x == '+' || x == '-')
	{
		return 1;
	}
	else if (x == '*' || x == '/')
	{
		return 2;
	}
	else if (x == '(' || x == ')')
	{
		return 0;
	}
	else return 0;
}



void Calculation::compare(char m, string n, string q)
{
	char temp2 = n[0];
	if (Calculation::priority(m) >= Calculation::priority(temp2))//優先級比棧頂運算符的較高或相等,也将運算符壓入棧1
	{
		m_S2.push(q);
	}
	else//否則将棧頂元素彈出并壓入棧2,将新棧頂元素繼續比較
	{
		m_S1.push(m_S2.top());
		m_S2.pop();
		if (!m_S2.empty())
		{
			compare(m, m_S2.top(), q);
		}
		else
		{
			string trans;
			trans += m;
			m_S2.push(trans);
		}
	}
}

int cal(int a, int b, char x)
{
	if (x == '+')
	{
		return a + b;
	}
	else if (x == '-')
	{
		return a - b;
	}
	else if (x == '*')
	{
		return a * b;
	}
	else if (x == '/')
	{
		if (b != 0)
		{
			return a / b;
		}
		else
		{
			printf("除數不能為零!");
			return 0;
		}
	}
	else return 0;
}



int Calculation::ToCalculate(queue<string>queue)
{
	int i;
	double num;
	string trans;
	char temp;
	string expression[101];
	for (i = 0; !queue.empty(); i++)//将表達式傳入string
	{
		expression[i] = queue.front();
		queue.pop();
	}
	i--;
	for (; i >= 0; i--)//從右至左掃描表達式
	{
		trans = expression[i];
		temp = trans[0];
		if (!isdigit(temp) && temp != '(' && temp != ')')//如果是運算符
		{
			if (m_S2.empty() || m_S2.top() == ")")
			{
				m_S2.push(trans);//如果棧2空或者棧	頂為右括号,直接壓入
			}

			else//否則需要與棧頂元素比較優先級
			{
				compare(temp, m_S2.top(), trans);
			}
		}

		else if (temp == '(')/*如果是左括号,依次彈出棧1頂的運算符,并壓入棧2,
							 直到遇到右括号為止,此時将這對括号舍棄*/
		{
			while (m_S2.top() != ")")
			{
				m_S1.push(m_S2.top());
				m_S2.pop();
			};
			m_S2.pop();
		}

		else if (temp == ')')//如果是右括号,直接壓入棧2中,
		{
			m_S2.push(trans);
		}
		
		else//數字存進另一個棧
		{
			m_S1.push(trans);
		}
	}

	while (!m_S1.empty())/*将棧1剩餘的運算符依次彈出并壓入棧2,棧2中即中綴
		表達式對應的字首表達式倒叙*/
	{
		m_S2.push(m_S1.top());
		m_S1.pop();
	}
	string expression1[101];
	for (i = 0; !m_S2.empty(); i++)//将棧中倒序的表達式存入string中,接下來開始計算。
	{
		expression1[i] += m_S2.top();
		m_S2.pop();
	}
	int j = i;
	for (i = 0; i < j; i++)//從右至左掃描表達式
	{
		if (isdigit(expression1[i][0]))//遇到數字
		{
			stringstream stream(expression1[i]);
			stream >> num;
			m_S3.push(num);//壓入棧中
		}
		else//遇到運算符
		{
			double temp1, temp2;
			temp1 = m_S3.top();
			m_S3.pop();
			temp2 = m_S3.top();
			m_S3.pop();
			double temp3 = cal(temp1, temp2, expression1[i][0]);//取出棧頂兩個數字進行計算後壓回棧中
			m_S3.push(temp3);
		}
	}
	return m_S3.top();//最後棧頂的數字就是答案
	m_S3.pop();
}
           

實作效果

面向對象程式設計第四次作業

總結

  • 這次作業的完成應該是算站在大神的肩膀上,參考了許多很早就完成的同學的作業,學習他們的方法,在自己編寫的過程中盡量學習使之成為自己的東西。
  • 通過這次作業學習了前中字尾表達式的轉換以及sstream對字元串及整形進行轉換。
  • 這一次的作業,雖然編寫過程對我來說有一些困難,但是發現自己還蠻喜歡debug的,觀察變量在調試過程中的變化情況,找到錯誤并修正能夠給我帶來一些成就感。
  • 其實每次在完成之後回頭看,其實問題并沒有一開始接手時感覺的那麼困難,隻要有了正确的方法,加上自己的耐心和思考,總是可以完成的。