c++生成算式並計算(《構建之法》第一章課后第一題)


c++實現計算器(自動生成算式並計算)

要滿足的需求有以下幾個:

  1. 自動生成隨機的四則運算算式,包含括號和小數。
  2. 對生成的算式計算出結果。
  3. 算式、結果分別存儲到不同的文件。

一 生成算式

由上述需求可知,算式中有運算符('+','-','*','/','(',')'),整數,小數(重點是有小數點),同時滿足程序模塊化設計的要求,所以使用STL中的string類存儲生成的算式。
生成算式時有幾點需要注意:

  • 首先生成一個數字,然后運算符('+','-','*','/')和數字交替出現,可以限定長度為奇數,在偶數位置(位置從0開始)生成數字,奇數位置生成運算符。
  • 生成數字有整數有小數。使用一個隨機變量控制生成的小數和整數的比例。
  • 生成小數時控制好位數、大小。
  • 生成括號時注意一個左括號一定要有一個右括號對應,因此設置一個變量存儲剩余要生成的右括號的數量,即每生成一個左括號該變量加一,沒生成一個右括號該變量減一。同時控制除非到了算式最后,不會出現一對括號只括住一個數字的情況。
    在程序中,以上這些由string GenerateExpression()實現,同時它還會調用int GenerateRightBracket()int GenerateLeftBracket() char GenerateOperator()double GeneratNumber() int GenerateInt()

二 中綴表達式轉為逆波蘭式

逆波蘭式即后綴表達式,棧可以方便的在計算機中計算后綴表達式的值。

將一個普通的中序表達式轉換為逆波蘭表達式的一般算法是:
首先需要分配2個棧,一個作為臨時存儲運算符的棧S1(含一個結束符號),一個作為輸入逆波蘭式的棧S2(空棧),S1棧可先放入優先級最低的運算符#,注意,中綴式應以此最低優先級的運算符結束。可指定其他字符,不一定非#不可。從中綴式的左端開始取字符,逐序進行如下步驟:

  • 若取出的字符是操作數,則分析出完整的運算數,該操作數直接送入S2棧
  • 若取出的字符是運算符,則將該運算符與S1棧棧頂元素比較,如果該運算符優先級(不包括括號運算符)大於S1棧棧頂運算符優先級,則將該運算符進S1棧,否則,將S1棧的棧頂運算符彈出,送入S2棧中,直至S1棧棧頂運算符低於(不包括等於)該運算符優先級,最后將該運算符送入S1棧。
  • 若取出的字符是“(”,則直接送入S1棧頂。
  • 若取出的字符是“)”,則將距離S1棧棧頂最近的“(”之間的運算符,逐個出棧,依次送入S2棧,此時拋棄“(”。
  • 重復上面的1~4步,直至處理完所有的輸入字符
  • 若取出的字符是“#”,則將S1棧內所有運算符(不包括“#”),逐個出棧,依次送入S2棧。

以上來自逆波蘭式-百度百科,完成以上步驟,S2棧便為逆波蘭式輸出結果。不過S2應做一下逆序處理。

在本程序中,使用隊列(queue)取代棧S2,省去逆序處理的步驟,這些步驟由函數queue<string> ConvertToRpn(string s,map<string,int>p,map<char,int>p_char)實現。

三 計算逆波蘭式

新建一個表達式,如果當前字符為變量或者為數字,則壓棧,如果是運算符,則將棧頂兩個元素彈出作相應運算,結果再入棧,最后當表達式掃描完后,棧里的就是結果。

計算功能由double Operation(queue<string> q)實現,同時它還會調用double Calculate(double n1, double n2, char c)

三 存儲到文件

程序運行結果包括單純的中綴表達式和含結果的中綴表達式,分別存儲到不同的文件。兩文件分別如下:


完整代碼

/*
	構建之法第一章習題一,實現自動生成四則運算的算式並判斷用戶計算的正誤。
	計划分三步走:
	1.自動生成算式
	2.輸入算式轉換為逆波蘭式
	3.計算算式結果
*/
#include<iostream>
#include<string>
#include<sstream>
#include<stack>
#include<queue>
#include<map>
#include<fstream>
using namespace std;

//將中綴表達式轉換為逆波蘭式
queue<string> ConvertToRpn(string s,map<string,int>p,map<char,int>p_char)
{
	int length = s.length();
	string temp_s="";
	string temp_for_push;
	stack<string>sk1;
	queue<string>sk2;
	sk1.push("#");
	for (int i = 0; i < length;)
	{
		if (isdigit(s[i]))
		{//判斷字符是否是0~9的數字
			while (isdigit(s[i]) || s[i] == '.')
			{
				temp_s = temp_s + s[i];
				i++;
			}
			sk2.push(temp_s);
			temp_s.clear();
		}
		else
		{
			if (s[i] == '+' || s[i] == '-' || s[i] == '*' || s[i] == '/'||s[i]=='^')
			{
				if (p_char[s[i]] >p[sk1.top()])
				{
					temp_for_push.clear();
					temp_for_push = temp_for_push + s[i];
					sk1.push(temp_for_push);
					i++;
				}
				else
				{
					while (p_char[s[i]] <= p[sk1.top()])
					{
						sk2.push(sk1.top());
						sk1.pop();
					}
					temp_for_push.clear();
					temp_for_push = temp_for_push + s[i];
					sk1.push(temp_for_push);
					i++;
				}
			}
			else if (s[i] == '(')
			{
				temp_for_push.clear();
				temp_for_push = temp_for_push + s[i];
				sk1.push(temp_for_push);
				i++;
			}
			else if(s[i]==')')
			{
				while (sk1.top() != "(")
				{
					sk2.push(sk1.top());
					sk1.pop();
				}
				sk1.pop();
				i++;
			}
		}
		if (i == length)
		{
			while (sk1.size() != 1)
			{
				sk2.push(sk1.top());
				sk1.pop();
			}
		}
	}
	return sk2;
}

//生成隨機小數
double GeneratNumber()
{
	double number;
	int temp;
	number = ((double)rand()) / ((double)(rand()/50));
	temp = number * 10;
	number = ((double)temp) / 10;
	number = number - (int)number + (int)number % 49;
	return number;
}

//生成隨機整數
int GenerateInt()
{
	double int_number;
	int_number = rand() % 49;
	return int_number;
}

//計算逆波蘭式中簡單表達式
double Calculate(double n1, double n2, char c){
	double result = 0;
	if (c == '+'){
		result = n1 + n2;
	}
	else if (c == '-'){
		result = n2 - n1;
	}
	else if (c == '*'){
		result = n1*n2;
	}
	else if (c == '/'){
		result = n2 / n1;
	}
	return result;
}

//計算逆波蘭式
double Operation(queue<string> q)
{
	stack<double> temp_for_digit;
	char temp_for_char;
	double temp_for_push = 0;
	double num1, num2;
	double temp_result = 0;
	int length = q.size();
	stringstream ss;
	while (q.size() != 0)
	{
		if (isdigit(q.front()[0]))
		{
			ss << q.front();
			ss >> temp_for_push;
			temp_for_digit.push(temp_for_push);
			q.pop();
			ss.clear();
		}
		else
		{
			temp_for_char = q.front()[0];
			q.pop();
			num1 = temp_for_digit.top();
			temp_for_digit.pop();
			num2 = temp_for_digit.top();
			temp_for_digit.pop();
			temp_result = Calculate(num1, num2, temp_for_char);
			temp_for_digit.push(temp_result);
		}
	}
	return temp_result;
}

//生成隨機運算符
char GenerateOperator()
{
	char result;
	int which = rand() % 6;
	if (which == 0 || which == 4)
	{
		result = '+';
	}
	else if (which == 1 || which == 5)
	{
		result = '-';
	}
	else if (which == 2)
	{
		result = '*';
	}
	else if (which == 3)
	{
		result = '/';
	}
	return result;
}

//生成左括號
int GenerateLeftBracket()
{
	int result = 0;
	int whether_bracket = rand() % 7;
	if (whether_bracket ==1)
	{
		result = 1;
	}
	return result;
}

//生成右括號
int GenerateRightBracket()
{
	int result = 0;
	int whether_bracket = rand() % 7;
	if (whether_bracket <= 5)
	{
		result = 1;
	}
	return result;
}

//生成表達式
string GenerateExpression()
{
	string expression = "";
	string temp_string;
	int count_right_bracket = 0;
	int length = 3;
	int location_for_last_bracket = 0;
	length += 2*(rand() % 15);
	stringstream ss;
	double temp_num;
	int whether_int = 0;
	int whether_bracket = 0;
	for (int i = 0; i < length; i++)
	{
		whether_int = rand() % 5;
		if (i % 2 == 0)
		{
			if (whether_int <= 3)
			{//80%生成整數
				temp_num = GenerateInt();
			}
			else
			{
				temp_num = GeneratNumber();
			}
			ss << temp_num;
			ss >> temp_string;
			expression += temp_string;
			ss.clear();
			if (count_right_bracket&&i>=location_for_last_bracket+3)
			{
				if (GenerateRightBracket())
				{
					count_right_bracket -= 1;
					expression += ')';
				}
			}
		}
		else
		{
			expression += GenerateOperator();
			whether_bracket= GenerateLeftBracket();
			if (whether_bracket == 1)
			{
				expression += '(';
				count_right_bracket += whether_bracket;
				location_for_last_bracket = i;
			}
		}
	}
	while ((count_right_bracket--) != 0)
	{
		expression += ')';
	}
	return expression;
}

int main()
{
	map<string, int> priorites;
	priorites["+"] = 1;
	priorites["-"] = 1;
	priorites["*"] = 2;
	priorites["/"] = 2;
	priorites["^"] = 3;
	map<char, int> priorites_char;
	priorites_char['+'] = 1;
	priorites_char['-'] = 1;
	priorites_char['*'] = 2;
	priorites_char['/'] = 2;
	priorites_char['^'] = 3;
	string expression;
	queue<string> RPN;
	double result;
	int count_expression;
	ofstream just_expression, answer;
	just_expression.open("expression.txt");
	answer.open("answer.txt");
	cout << "how many expressions do you want: " << endl;
	cin >> count_expression;
	for (int i = 0; i<count_expression; i++)
	{
		expression = GenerateExpression();
		RPN = ConvertToRpn(expression,priorites,priorites_char);//得到后綴表達式
		result = Operation(RPN);
		just_expression << i+1 << ".  " << expression << endl;
		answer << i+1 << ".  " << expression << " = " << result << endl;
		expression.clear();
		RPN = queue<string>();//清空當前隊列
	}
	just_expression.close();
	answer.close();
	cout << "finished" << endl;
	system("pause");
	return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM