zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    系统架构师学习笔记_第十一章(下)
    通过IronRuby和C#学习RUBY系列[0]
    TIPS to comment your code
    超级简单:DIV布局
    js 查询XML数据添加到HTML select控件
    《架构之美》读书笔记(一)
    18个不常见的C#关键字,您使用过几个?
    如何成为人尽皆知的C#开发人员
    实现Visual Studio 2010一个很简单的很酷的扩展
    一种简单的直观的高效的权限设计
  • 原文地址:https://www.cnblogs.com/thechosenone95/p/9826744.html
Copyright © 2011-2022 走看看