四则运算表达式生成

软件工程大作业的结对项目–四则运算题目生成器

讲述的是前两个阶段的需求分析,设计和实现

上一篇文章的链接

概要设计和详细设计

类的选择

有三个类,分别是存储运算符和运算数节点的二叉树类 BiTree,生成四则运算表达式的类 QuestGenerator和计算表达式结果的类solvable。QuestGenerator中的方法调用Bitree中的方法,将运算符和运算数保存在树节点中,然后生成表达式,接着调用solvable中的方法计算答案

uml图

用例图

类图

顺序图

精化类的设计

BiTree类

属性部分
有lchild rchild this_level value这四个数据结构

方法部分
分别是getOperOrder获得当前符号优先级 set_lchild设置左子树 set_rchild设置右子树 to_string将表达式转换为一字符串

QuestGenerator类

属性部分
有output_list和deduplicate_set这两个数据结构

方法部分
generate方法构建一棵二叉树
其中调用了solvable类的方法solve求解表达式
deduplicate方法给表达式判重
format方法交换左右子树
change_pow方法转换乘方符号
round_up方法对结果进行四舍五入

solvable类

属性部分,是prior这个数据结构

方法部分,calculator方法转换成逆波兰表达式,调用solve方法分步求解

实现

首先生成四则运算表达式,用父节点表示符号,叶子结点表示运算符,这样构成一棵二叉树可以用来表达一个完整的四则运算表达式,通过对这棵二叉树进行中序遍历,得到中序表达式。对于表达式的运算和结果输出,进行后序遍历,转化为逆波兰表达式,方便计算机进行计算

表达式生成:
首先随机的生成一系列树节点,父节点是运算符,叶子节点是运算数,将生成的节点保存在存储节点的二叉树类中
接下来通过一个新类从刚才生成的节点中随机选取一个运算符和两个运算数或者两个运算符或者一个运算符一个运算数生成表达式

用到的两个类如下:

存储四则表达式节点的二叉树类
class BiTree:def getOperOrder(self, ch):if ch in ['+', '-']:return 0elif ch in ['*']:return 2elif ch in ['/']:return 3elif ch == '^':return 4def __init__(self, node_type=0, val=0):self.node_type = node_typeself.val = valself.lchild = Noneself.rchild = Noneif self.node_type == 1:self.val = chr(self.val)self.this_level = self.getOperOrder(self.val)def set_lchild(self, lchild):self.lchild = lchilddef set_rchild(self, rchild):self.rchild = rchilddef to_string(self, upper_level=0):if self.node_type == 1:if upper_level > self.this_level or upper_level == self.this_level == 3 or upper_level == self.this_level \== 4:return '(' + self.lchild.to_string(self.this_level) + self.val + self.rchild.to_string(self.this_level + 1) + ')'else:return self.lchild.to_string(self.this_level) + self.val + self.rchild.to_string(self.this_level + 1)if int(self.val) < 0:return '(' + str(self.val) + ')'return str(self.val)
生成四则运算表达式的生成类

类中定义的方法是generate deduplicate format_expression round_up change_pow_operator
generate是构建一棵二叉树
其中调用了solvable类的方法solve对生成的表达式求解
deduplicate是判断生成的表达式中是否有重复的(包括满足交换律的运算符左右子树交换后重复的情况)
format用于交换左右子树
change_pow表示是否需要更改表达式的乘方符号
round_up是对计算结果进行四舍五入

class QuestGenerator:def __init__(self):self.output_list = []self.deduplicate_set = set()def generate(self, quantity=1, operators=7, if_false=False, if_pow=False, if_fraction=False, pow_operator=False,max=9):sum = 0while sum < quantity:filled_ops, unfilled_ops = self.randinit(operators=operators, if_false=if_false, if_pow=if_pow, max=max)while len(unfilled_ops):i = random.randint(0, len(filled_ops) - 1)unfilled_ops[0].set_lchild(filled_ops[i])filled_ops.pop(i)i = random.randint(0, len(filled_ops) - 1)unfilled_ops[0].set_rchild(filled_ops[i])filled_ops.pop(i)filled_ops.append(unfilled_ops[0])unfilled_ops.pop(0)if self.deduplicate(filled_ops[-1]):print('Duplicated!')continuestring = filled_ops[-1].to_string()solve = Solvable()k = solve.calculator(string)if k == 'not solvable':continueif not if_fraction:k = self.round_up(round(float(k.numerator / k.denominator), 3))sum = sum + 1string = self.changepowop(string, pow_operator)self.output_list.append(string)self.output_list.append(str(k))def deduplicate(self, root: BiTree):inspect = deepcopy(root)self.format_expression(inspect)if inspect.to_string() in self.deduplicate_set:return Trueelse:self.deduplicate_set.add(inspect.to_string())return Falsedef randinit(self, operators, if_false, if_pow, max):operands = ['+', '-', '*', '/', '^']if if_false:nums = [BiTree(0, random.randint(-max, max)) for _ in range(operators + 1)]else:nums = [BiTree(0, random.randint(0, max)) for _ in range(operators + 1)]if if_pow:ops = [BiTree(1, ord(operands[random.randint(0, 4)])) for _ in range(operators)]else:ops = [BiTree(1, ord(operands[random.randint(0, 3)])) for _ in range(operators)]return nums, opsdef format_expression(self, node: BiTree):if not node.lchild:returnself.format_expression(node.lchild)self.format_expression(node.rchild)if node.this_level in (0, 2) and node.lchild.to_string() > node.rchild.to_string():tmp = node.lchildnode.lchild = node.rchildnode.rchild = tmpdef round_up(self, value):return Decimal(value).quantize(Decimal('0.00'), rounding='ROUND_HALF_UP')def changepowop(self, string: str, pow_operator):if pow_operator:return string.replace('^', '**')return string
表达式运算的类

solvable类中,Calculator是把算式转化成逆波兰表达式,其中opt列表中是运算符,data列表中是运算数。在Calculator中调用solve方法进行分步求解,solve返回当前的局部运算结果,继续参与运算。其中分数的乘方运算将分子和分母分别做乘方,然后相除。若解过大过小或除0,发现生成的这个题不可解,那么返回‘not solvable’

solvable类代码如下:

from fractions import Fractionclass Solvable:prior = {'+': 0, '-': 0, '*': 1, '/': 1, '^': 2, '(': -1}def solve(self, num1: Fraction, num2: Fraction, operator):if operator == '+':return num1 + num2elif operator == '-':return num2 - num1elif operator == '/':if num1 == 0:return 'not solvable'return num2 / num1elif operator == '*':return num2 * num1elif operator == '^':k1 = num2.denominatork2 = num2.numeratorif num1 == 0:return Fraction(1, 1)elif num1 >= 5 or num1 <= 0.2 or num2 >= 100 or num2 <= 0.01:return 'not solvable'k2 = pow(int(k2), float(num1))k1 = pow(int(k1), float(num1))if k2.is_integer() and k1.is_integer():return Fraction(int(k2), int(k1))else:return 'not solvable'def calculator(self, line):opt = []data = []i = 0while i < len(line):start = iif line[i] == '(':if line[i + 1] == '-':i += 1while line[i + 1].isdigit() and i + 1 < len(line):i += 1data.append(Fraction(int(line[start + 1:i + 1]), 1))i += 1else:opt.append(line[i])elif line[i].isdigit():while i + 1 < len(line) and line[i + 1].isdigit():i += 1data.append(Fraction(int(line[start:i + 1]), 1))elif line[i] == ')':while opt[-1] != '(':k = self.solve(data.pop(), data.pop(), opt.pop())if k == 'not solvable':return 'not solvable'data.append(k)opt.pop()else:while opt and self.prior[line[i]] <= self.prior[opt[-1]]:k = self.solve(data.pop(), data.pop(), opt.pop())if k == 'not solvable':return 'not solvable'data.append(k)opt.append(line[i])i += 1while opt:k = self.solve(data.pop(), data.pop(), opt.pop())if k == 'not solvable':return 'not solvable'data.append(k)k = data.pop()if k.denominator > 5000 or k.numerator > 5000:return 'not solvable'return k

main函数作为接口调用这些类,需要用户选择的参数有数据个数,操作符个数,算式中是否要负数,是否要乘方,是否要分数,选哪个乘方符号和最大操作数大小。

import OriginRequest as QRdef answer(quantity: int, list: list, if_fraction=0):i = 0correct = 0while i < list.__len__():if i % 2 == 0:print(list[i], '=')else:if if_fraction:st = input('answer:')if st == list[i]:correct += 1else:print('uncorrect')else:st = input('answer:')st = float(st)if st == float(list[i]):correct = correct + 1else:print('uncorrect')i = i + 1print('correct num', correct)print('wrong num', quantity - correct)if __name__ == '__main__':quantity = input('quantity:')operators = input('operator nums:')if_false = input('negative operands:')if_pow = input('pow operators:')if_fraction = input('fraction present:')Pow_Operand = input('pow_operator:')max = input('max nums:')g = QR.QuestGenerator()g.generate(quantity=int(quantity), operators=int(operators), if_false=int(if_false), if_pow=int(if_pow),if_fraction=int(if_fraction), pow_operator=int(Pow_Operand), max=int(max))answer(int(quantity),g.output_list,int(if_fraction))

程序运行结果:

测试和完善

测试和完善部分链接如下
软件工程项目 四则运算表达式生成----6

软件工程项目 四则运算表达式生成----2相关推荐

  1. 软件工程项目 四则运算表达式生成----5

    四则运算题目生成器 软件工程大作业的结对项目–四则运算题目生成器 写的是需求分析中的功能需求第四阶段的过程和内容 需求分析阶段的链接如下 软件工程项目 四则运算表达式生成----1 网页之前的功能需求 ...

  2. java生成算数表达式_惊!小学生要失业了,Java实现生成并计算四则运算表达式。...

    githup传送门:https://github.com/Bubblegod/FormulationCalculation 项目成员:梁竞 袁智杰 1.项目要求 题目:实现一个自动生成小学四则运算题目 ...

  3. c语言整数四则运算表达式的输出格式控制,四则运算

    网页简易四则运算器2021-05-18 22:35:40 下载地址:https://download.csdn.net/download/qq_31293575/18340399 项目介绍 Calcu ...

  4. 【软件工程基础】结对项目之四则运算题目生成

    [软件工程基础]结对项目之四则运算题目生成 一,项目介绍 项目的github地址:https://github.com/qqqqqianru/sizeyunsuantimushengcheng 二.项 ...

  5. 作业 20180925-6 四则运算试题生成

    此作业要求参见:https://edu.cnblogs.com/campus/nenu/2018fall/homework/2148 此作业代码地址:https://git.coding.net/ti ...

  6. 罗杨美慧 20190919-6 四则运算试题生成,结对

    本次作业要求参见:[https://edu.cnblogs.com/campus/nenu/2019fall/homework/7631] 结对伙伴:徐丽君 功能1  四则运算 支持出题4个数的四则运 ...

  7. c语言求不定式的最大值,C语言之四则运算表达式求值(链栈)—支持浮点型数据,负数, 整型数据运算...

    运算符间的优先级关系: 链栈结构体定义: 数据域使用字符串长度为20的字符数组(故需要注意判断读取的字符串是运算符还是数值) 可支持浮点型数据,负数, 整型数据的运算 float EvaluateEx ...

  8. 软件工程项目基于java的wc实现

    WC软件工程项目JAVA实现博客 github地址:https://github.com/liudaohu/myrepository.git 功能实现 ·    -w 统计单词数 -c 统计字符数 - ...

  9. 软件工程第四次作业-四则运算试题生成

    四则运算试题生成 博客园地址:http://www.cnblogs.com/liuyaoze/ git地址:https://git.coding.net/Vector121/f4.git 要求1: ( ...

最新文章

  1. 《数据分析实战 基于EXCEL和SPSS系列工具的实践》一3.4 数据量太大了怎么办
  2. centos 7 局域网丢包排查_ethtool原理介绍和解决网卡丢包排查思路
  3. 内存四区 malloc/free与new/delete的区别
  4. 监督学习无监督学习_无监督学习简介
  5. hdu1686:KMP板子
  6. Maven学习(三)————Maven核心概念(二)
  7. 基于mybatis-generator代码生成工具改(链式方法实体版)
  8. Microsoft Surface--Bing™ Maps WPF Control
  9. linux 下挂载光驱
  10. MySQL中的时间函数
  11. 计算机启用远程桌面连接失败,开启局域网远程桌面连接不上怎么办
  12. java子网掩码计算器_java 子网掩码计算
  13. 中国当代社会阶层分析——看看你处在社会的哪个阶层?
  14. IPFS - 可快速索引的版本化的点对点文件系统
  15. mp4视频解码生成图片
  16. 智慧楼宇篇 6 —— 室内定位技术(五) - 室内定位技术总结
  17. 【LeetCode】1160. 拼写单词(C++)
  18. 无法从命令行或调试器启动服务,必须首先安装Windows服务(使用installutil.exe),然后用ServerExplorer、Windows服务器管理工具或NET START命令启动它
  19. SpringBoot+OAuth2+JWT实现单点登录SSO完整教程,竟如此简单优雅!
  20. VLAN--虚拟局域网

热门文章

  1. DjangoQQ登录之定义QQ登录工具QQLoginTool(QQLoginTool介绍、QQLoginTool安装、QQLoginTool使用说明)
  2. 关于16进制0x的理解
  3. java将date类型转成yyyymmdd_Java中Date转换大全,返回yyyy-MM-dd的Date类型
  4. 漏洞扫描处理:凝思6.0.80操作系统安装数据库Mysql 8.0.27(二进制安装包安装)
  5. 【UCenter】站点整合ucenter与discuz实现单点登录
  6. 去“碳”路,去助力可再生能源电力系统
  7. MPS | 光伏可再生能源利用 — 北京冬奥的另一块“金牌”
  8. Wavemaker和 apache cordova混合开发之圖片上傳
  9. 《从零开始学架构》一:基础架构
  10. R语言-模糊逻辑控制