zoukankan      html  css  js  c++  java
  • 课程作业(六)


    GitHub develop


    表达式部分的实现过程

    表达式的生成部分主要过程由流程图展示。完整的表达式可以分解成一个个a+b的小表达式,所以通过生成a+b就可以拼接成一个完整的表达式。在生成过程中,通过对分数、括号的存在与否的各种情况的判断,丰富了表达式的类型,增强了最终结果的随机性。并且,只要各个小表达式是合法的,那么最终拼接而成的表达式就会是合法的,所以不需要对表达式的格式进行合法性检验。

    生成一个完整的表达式后,再对其进行唯一性和除零的检验,符合要求的话就放进表达式的集合中,否则就重新生成。

    刚生成的表达式为中缀表达式,在计算部分,先将其转换为后缀表达式,再进行得数的计算。表达式的转换和后缀表达式的计算都是通过实现的。

    此处输入图片的描述


    代码

    这里贴了expression类的除头文件外的完整代码,包含了表达式的生成、检验和计算。

    /*************************************************************
    文件名:Expression.cpp
    作者:许郁杨 日期:2017/05/08
    描述: 表达式类
    主要功能包括:表达式的生成、检验和计算
    
    作者:许郁杨 日期:2017/05/10
    更新:补充了注释,对格式排版进行一些调整
    *************************************************************/
    #include"expression.h"
    #include<iostream>
    #include<sstream>
    #include<vector>
    #include<stack>
    using namespace std;
    
    Expression::Expression() { }
    
    /*随机生成一个运算符 日期:2017/05/07
      更新:注释补充,格式调整 日期:2017/05/10*/
    char Expression::RandomOperation(char ifMultiplyDivide)
    {
    	int tmp;
    	if (ifMultiplyDivide == 'y')//允许乘除 
    	{
    		tmp = RandomNumber(1, 4);
    		switch (tmp)
    		{
    		case 1:
    		{
    			return '+';
    			break;
    		}
    		case 2:
    		{
    			return '-';
    			break;
    		}
    		case 3:
    		{
    			return '*';
    			break;
    		}
    		case 4:
    		{
    			return '/';
    			break;
    		}
    		}
    	}
    	else//不允许乘除
    	{
    		tmp = RandomNumber(1, 2);
    		switch (tmp)
    		{
    		case 1:
    		{
    			return '+';
    			break;
    		}
    		case 2:
    		{
    			return '-';
    			break;
    		}
    		}
    	}
    }
    
    /*判断表达式是否唯一,重复为false,唯一为true 日期:2017/05/07
      更新:注释补充,格式调整 日期:2017/05/10*/
    bool Expression::IsOnly(string expression)
    {
    	int count = 0;
    	for (unsigned i = 0; i < m_expressionUint.size(); i++)
    	{
    		if (expression != m_expressionUint[i])
    		{
    			count++;
    		}
    		else
    		{
    			break;
    		}
    	}
    	if (count == m_expressionUint.size())//如果为唯一
    	{
    		return true;
    	}
    	else//如果重复
    	{
    		return false;
    	}
    }
    
    /*生成一个中缀表达式 日期:2017/05/07
      更新:注释补充,格式调整 日期:2017/05/10*/
    string Expression::GenerateInfixExpression(int low, int high, int parameterNumber, char ifMultiplyDivide, char ifFraction, char ifBracket)
    {
    	string expression;//表达式
    	for (; ;)
    	{
    		string parameter1, parameter2;//表达式的参数
    		bool ifFirst = true;//是否已生成第一个小表达式,是为true,否为false
    		for (int j = 0; j < parameterNumber - 1; j++)
    		{
    			int ntmp;
    			char sign = RandomOperation(ifMultiplyDivide);//运算符
    
    			if (ifFraction == 'y')//允许分数 
    			{
    				ntmp = RandomNumber(1, 3);
    				switch (ntmp)
    				{
    				case 1://整数和整数 
    				{
    					stringstream sstmp1, sstmp2;
    					sstmp1 << RandomNumber(low, high);
    					sstmp1 >> parameter1;
    					sstmp2 << RandomNumber(low, high);
    					sstmp2 >> parameter2;
    					sstmp1.clear();
    					sstmp2.clear();
    					break;
    				}
    				case 2://整数和真分数 
    				{
    					stringstream sstmp;
    					sstmp << RandomNumber(low, high);
    					sstmp >> parameter1;
    					sstmp.clear();
    					Fraction fraction2;
    					fraction2.GetFraction(low, high);
    					fraction2.Simplify();
    					parameter2 = fraction2.TransferIntoStringNoInt();
    					break;
    				}
    				case 3://分数和分数 
    				{
    					Fraction fraction1, fraction2;
    					fraction1.GetFraction(low, high);
    					fraction1.Simplify();
    					fraction2.GetFraction(low, high);
    					fraction2.Simplify();
    					parameter1 = fraction1.TransferIntoStringNoInt();
    					parameter2 = fraction2.TransferIntoStringNoInt();
    					break;
    				}
    				}
    			}
    			else//不允许分数
    			{
    				stringstream sstmp1, sstmp2;
    				sstmp1 << RandomNumber(low, high);
    				sstmp1 >> parameter1;
    				sstmp2 << RandomNumber(low, high);
    				sstmp2 >> parameter2;
    				sstmp1.clear();
    				sstmp2.clear();
    			}
    			if (ifBracket == 'y')//允许括号
    			{
    				ntmp = RandomNumber(1, 4);
    				switch (ntmp)
    				{
    				case 1://无括号
    				{
    					if (ifFirst)
    					{
    						expression = parameter1 + sign + parameter2;
    						ifFirst = false;
    					}
    					else
    					{
    						expression = expression + sign + parameter1;
    					}
    					break;
    				}
    				case 2://无括号
    				{
    					if (ifFirst)
    					{
    						expression = parameter2 + sign + parameter1;
    						ifFirst = false;
    					}
    					else
    					{
    						expression = parameter1 + sign + expression;
    					}
    					break;
    				}
    				case 3://有括号
    				{
    					if (ifFirst)
    					{
    						expression = "[" + parameter1 + sign + parameter2 + "]";
    						ifFirst = false;
    					}
    					else
    					{
    						expression = "[" + expression + sign + parameter1 + "]";
    					}
    					break;
    				}
    				case 4://有括号
    				{
    					if (ifFirst)
    					{
    						expression = "[" + parameter2 + sign + parameter1 + "]";
    						ifFirst = false;
    					}
    					else
    					{
    						expression = "[" + expression + sign + parameter1 + "]";
    					}
    					break;
    				}
    				}
    			}
    			else//不允许括号
    			{
    				ntmp = RandomNumber(1, 2);
    				switch (ntmp)
    				{
    				case 1:
    				{
    					if (ifFirst)
    					{
    						expression = parameter1 + sign + parameter2;
    						ifFirst = false;
    					}
    					else
    					{
    						expression = expression + sign + parameter1;
    					}
    					break;
    				}
    				case 2:
    				{
    					if (ifFirst)
    					{
    						expression = parameter2 + sign + parameter1;
    						ifFirst = false;
    					}
    					else
    					{
    						expression = parameter1 + sign + expression;
    					}
    				}
    				}
    			}
    		}
    		m_infix = expression;
    		if ((IsOnly(expression)) && (CalculateResult() != "non_comformance"))//判断新生成的表达式是否重复以及是否出现除0的情况
    		{
    			m_expressionUint.push_back(expression);
    			break;
    		}
    	}
    	return expression;
    }
    
    /*将中缀表达式转化为后缀表达式 日期:2017/05/07
      更新:注释补充,格式调整 日期:2017/05/10*/
    void Expression::TransferInfixIntoPostfix()
    {
    	unsigned i = 0;
    	int j = 0;
    	stack<char> signStack;//符号栈
    	while (i < m_infix.size())
    	{
    		if ((m_infix[i] >= '0') && (m_infix[i] <= '9'))//判断数字 
    		{
    			while ((m_infix[i] >= '0') && (m_infix[i] <= '9'))
    			{
    				m_postfix[j] = m_infix[i];
    				i++;
    				j++;
    			}
    			m_postfix[j] = '!';//标识单个整数 
    			j++;
    		}
    		if (m_infix[i] == '(')//判断分数 
    		{
    			while (m_infix[i] != ')')//将分数作为整体 
    			{
    				m_postfix[j] = m_infix[i];
    				i++;
    				j++;
    			}
    			m_postfix[j] = m_infix[i];
    			i++;
    			j++;
    		}
    		if ((m_infix[i] == '+') || (m_infix[i] == '-'))//判断'+'、'-' 
    		{
    			while ((!signStack.empty()) && (signStack.top() != '['))
    			{
    				m_postfix[j] = signStack.top();
    				j++;
    				signStack.pop();
    			}
    			signStack.push(m_infix[i]);
    		}
    		if ((m_infix[i] == '*') || (m_infix[i] == '/'))//判断'*'、'/' 
    		{
    			while ((!signStack.empty()) && (signStack.top() != '[') && ((signStack.top() == '*') || (signStack.top() == '/')))
    			{
    				m_postfix[j] = signStack.top();
    				j++;
    				signStack.pop();
    			}
    			signStack.push(m_infix[i]);
    		}
    		if (m_infix[i] == '[')//判断'['
    		{
    			signStack.push(m_infix[i]);
    		} 
    		if (m_infix[i] == ']')//判断']' 
    		{
    			while (signStack.top() != '[')
    			{
    				m_postfix[j] = signStack.top();
    				j++;
    				signStack.pop();
    			}
    			signStack.pop();
    		}
    		i++;
    	}
    	while (!signStack.empty())//当有残余运算符时 
    	{
    		m_postfix[j] = signStack.top();
    		j++;
    		signStack.pop();
    	}
    	m_postfix[j] = '';//设置终止符 
    }
    
    /*计算后缀表达式的值 日期:2017/05/07
      更新:注释补充,格式调整 日期:2017/05/10*/
    string Expression::CalculateResult()
    {
    	int i = 0;
    	int point = -1;//栈顶指针
    	bool ifDivideZero = false;//是否除零,是为true,否为false
    	Fraction numberStack[kMax];//数栈
    	TransferInfixIntoPostfix();
    	while ((m_postfix[i] != '') && (i<1000))
    	{
    		if ((m_postfix[i] >= '0') && (m_postfix[i] <= '9'))//整数入栈 
    		{
    			double k = 0;//int会计算出错 
    			while ((m_postfix[i] >= '0') && (m_postfix[i] <= '9'))
    			{
    				k = 10 * k + m_postfix[i] - '0';
    				i++;
    			}
    			point++;
    			numberStack[point].TransferIntIntoFraction(k, 1);
    		}
    		else
    			if (m_postfix[i] == '(')//分数入栈 
    			{
    				double up = 0, down = 0;//int会计算出错 
    				i++;
    				while (m_postfix[i] != '\')
    				{
    					up = 10 * up + m_postfix[i] - '0';
    					i++;
    				}
    				i++;
    				while (m_postfix[i] != ')')
    				{
    					down = 10 * down + m_postfix[i] - '0';
    					i++;
    				}
    				point++;
    				numberStack[point].TransferIntIntoFraction(up, down);
    			}
    			else//进行计算
    			{
    				point--;
    				switch (m_postfix[i])
    				{
    				case '+':
    				{
    					numberStack[point] = numberStack[point] + numberStack[point + 1];
    					break;
    				}
    				case '-':
    				{
    					numberStack[point] = numberStack[point] - numberStack[point + 1];
    					break;
    				}
    				case '*':
    				{
    					numberStack[point] = numberStack[point] * numberStack[point + 1];
    					break;
    				}
    				case '/':
    				{
    					if (numberStack[point + 1].isDivisorZero())//如果除数为零
    					{
    						ifDivideZero = true;
    					}
    					numberStack[point] = numberStack[point] / numberStack[point + 1];
    				}
    				}
    			}
    		i++;
    	}
    	if ((!ifDivideZero) && (numberStack[point].IsInt()))//如果没有除零以及得数为整数
    	{
    		return numberStack[point].TransferIntoString();
    	}
    	else
    	{
    		return "non_comformance";
    	}
    }
    

    运行结果截图

    此处输入图片的描述


    MFC对话框创建

    MFC,全称微软基础类库,是一个微软公司提供的类库(class libraries),以C++类的形式封装了Windows API,并且包含一个应用程序框架,以减少应用程序开发人员的工作量。通过它可以非常方便地进行c++的界面化开发

    由于是初学,这里只整理一些基本的对话框程序的操作。

    首先是对话框程序的创建:

    先新建一个MFC应用程序

    此处输入图片的描述

    然后选择基于对话框,之后就一方通行了,中间的例如最大、最小化之类的选项可以自行选择。

    此处输入图片的描述

    创建完之后,首先要按照自己的需要在对话框中添加各式各样的小控件,选择视图中的工具箱,或者直接点击侧边栏的工具箱,这样更方便些。

    此处输入图片的描述

    然后通过对各个控件属性的Caption进行更改,就能改变它们显示的文字。粗糙排版如下:

    此处输入图片的描述


    MFC对话框编程

    写代码前,先要对控件右键添加变量类别中选择Value,然后选择类型,填写变量名。这样就能够在程序中改变控件的内容。

    此处输入图片的描述

    双击控件后就能对相应控件添加代码了,这里贴上生成算式的按钮的代码。

    void CMFCApplication5Dlg::OnBnClickedButton3()
    {
    	// TODO: 在此添加控件通知处理程序代码
    	UpdateData();
    	string tmp;
    	tmp = expression.GenerateInfixExpression(0, 10, 4, 'y', 'y', 'y');
    	equation = tmp.c_str();
    	UpdateData(FALSE);
    }
    

    注意点和可能碰到的问题

    • UpdataData():在访问变量前调用UpdateData(TRUE),就能够得到用户在控件中输入的内容;在修改变量后调用UpdateData(FALSE),就能使控件显示更新后的内容。

    • #include "stdafx.h":这个头文件中包含了对MFC标准头文件(如Windows.H、Afxwin.H)预先编译的信息,编译器通过stdafx.h来使用预编译头文件。因此,所有的MFC文件的第一条语句都是:#include "stdafx.h",在它前面的所有代码将被忽略。如果不加就会提示编译错误。

    • 有同学在创建MFC项目时可能会碰到找不到rcdll.dll文件的问题。百度上的解决方法主要有两种:

    • 第一种是在注册表中找到:HKEY_CURRENT_USER/Software/Microsoft/Microsoft SDKs/Windows在windows项中如果存在以下两项就修改为下列示例,如果没有新建如下两项并设置相应值:

      • X86系统:"CurrentVersion"="v7.0a" "CurrentInstallFolder"="C://Program Files//Microsoft SDKs//Windows//v7.0A//"
      • X64系统:"CurrentVersion"="v7.0a" "CurrentInstallFolder"="C://Program Files (x86)//Microsoft SDKs//Windows//v7.0A//"
    • 第二种是直接把C:Program Files (x86)Microsoft SDKsWindowsv7.0Ain
      目录下的rcdll.dll拷贝到C:Program Files(x86)Microsoft Visual Studio 10.0VCin(路径因人而异)

    • 最简单的方法还是直接找有rcdll.dll文件的同学拷贝一份过去,更简单方便。这里提供我上传的一份的链接:百度云 密码:l2u3


    代码

    这里贴上两个按钮的代码。

    Expression expression;
    void CMFCApplication5Dlg::OnBnClickedButton3()
    {
    	// TODO: 在此添加控件通知处理程序代码
    	UpdateData();
    	string tmp;
    	tmp = expression.GenerateInfixExpression(0, 10, 4, 'y', 'y', 'y');
    	equation = tmp.c_str();
    	UpdateData(FALSE);
    }
    
    void CMFCApplication5Dlg::OnBnClickedButton1()
    {
    	// TODO: 在此添加控件通知处理程序代码
    	UpdateData();
    	string result = expression.CalculateResult();
    	CString tmp1;
    	tmp1 = result.c_str();
    	if (answer == tmp1)
    	{
    		responce = "正确";
    	}
    	else
    	{
    		CString tmp2;
    		tmp2 = "错误,正确答案是";
    		responce = tmp2 + tmp1;
    	}
    	UpdateData(FALSE);
    }
    

    运行结果截图

    此处输入图片的描述

    此处输入图片的描述

    此处输入图片的描述


    心得体会

    之前在编写多语言功能时,因为想用stringtable来实现,所以学过MFC中通过stringtable实现自动切换语言的操作,因此这次对话框的简单实现并没有碰到什么困难。由于之前的代码中完善了各个类的编写,所以在改写到对话框中时也很方便。但是,对话框的局限也相当明显,之前实现的各个功能若是都铺在一个框中就会显得特别臃肿。我想在熟悉对话框编程之后,就开始把原本的程序改成一个单文档程序。不过界面化还是相当复杂的,现在对各种函数和功能还是一知半解。。


    参考链接

    VC2008以资源形式实现多语言版本(非Unicode)
    VS2010/MFC编程入门教程之目录和总结

  • 相关阅读:
    IsIconic() OnPaint里的用途
    中值滤波
    一个小学生题库生成器
    音视频同步
    [转]字符编码笔记:ASCII,Unicode和UTF8
    项目中常见bug及解决方法
    TSQL基础chp10可编程对象学习笔记[上]
    使用UdpAppender时出现了“使用了与请求协议不兼容的地址”的解决办法
    .net gridview 任意单击某行跳转到新的页面,并且新页面的参数来自于与gridview中的不可见字段
    数组去重的四种方法
  • 原文地址:https://www.cnblogs.com/S031602240/p/6922405.html
Copyright © 2011-2022 走看看