小学生四则运算出题软件-基于python控制台的实现

一、题目要求:个人作业1——四则运算题目生成程序(基于控制台)

二、核心算法:

1、基于递归的四则运算式子生成算法:

 

说明:对于四则运算二叉树的查重问题,因为百度铺天盖地地都是使用:随机生成式子->翻译出后缀二叉树->规范化为二叉树->查重 的方式来实现生成并查重四则运算式子的套路,为此本人试着尝试了一下使用递归方法循环嵌套生成
运算式子并嵌套,尽管写的过程中踩了不少坑,但最终还是实现了整个算法,尽管还存在着一些诟病,还请大佬们多多指点。

递归思想:递归生成四则运算表达式大致的思路是,每一层递归式子都代表一层式子,式子的左部或右部可能为一个数也可能为一个式子,例(3*5)+2,(3*5)为式子的左部,2为式子的右部,+为当前式子的操作符,递归函数有一参数

count,代表当前次递归所代表的式子所包含的操作数,每次递归都将分配当前可支配的操作数count随机产生左右子树,再随机生成一操作符,最后根据上下文分析是否要对左子树或者右子树加上括号,最后递归函数同时返回三个
数据:当前式子规范化后的二叉树,显示给用户的表达式,以及当前式子对应的答案,即在递归的过程中实时更新信息,当递归结束时该对象所需要的全部信息均已产生,个人感觉这也是递归生成四则运算表达式的亮点之一。


 递归过程中的数据结构

  1、questionArray:表示规范化后的二叉树,在此处中使用[左子树,符号,右子树]来表示,其中左子树或右子树若也为式子也用这种结构来表示,符号分别用1234表示+-*/,例[[3,2,5],3,[2,4,3]]可转换为[[3,-,5],*,[2,/,3]],最终表示为(3-5)*(2/3),表示成二叉树对应结  构如下。

 

  2、expression:表示呈现给用户看的表示式字符串。

  3、answer:表示当前式子对应的答案,由于答案中可能出现分数,故此处使用列表[分子,分母]的形式来表示答案。

算法详情
 1、首先设置递归函数的出口,当且仅当参数count等于1时,此时当前递归所代表的式子仅有一个操作数,故直接返回一个数字对应的数据对象。
  

2、在else中设置递归时的正常处理情况,首先需要将当前递归所包含的操作数个数分配给左子树和右子树中,已达到式子中可以出现两个不相交括号的情况,然后将随机分配给左右子树的操作数个数作为参数,继续递归左右子树。
  

3、之前程序会循环递归直至底层叶子节点返回具体的随机数,最后左右子树的递归结束并返回对应的数据对象,需对左右子树的数据对象进行对应的计算以返回该式子自身的数据对象,首先随机生成操作符,之后针对表达式是否加括号的情况,个人
作出以下约束,对于加不加括号不改变计算继续的一律不加括号。则针对每次左右子树递归结束后,需要对左子树加括号的情况即为当左子树内部操作为+-,当前操作为*/时,左子树表达式需要加上括号,其余情况一律无需加括号。而对于右子树的括号
情况同理也可能得当且仅当右子树内部操作为*/,当前操作为+-时,右子树不需要加括号,其余情况一律需要加括号。
  

 

 4、最后根据左右子树的数据计算出当前递归的规范化二叉树以及计算结果,规范化二叉树的生成过程较为复杂将在下面介绍,最后将组装好的3个数据返回给上一层递归。

 5、最后,递归结束时将返回三个数据并存储之,至此一个表达式的生成结束。

 

2、查重:

 

说明:查重可以说是这个四则运算出题软件最鸡肋的一个问题,不理他的话,如果出题数字范围小且出题数目大的话隔三差五的会出重复的题,但是完全解决的话所花的精力和时间又太过了。此次关于查重问题我并没有实现百分百查重,因为
个人感觉相比于出现重复题目的概率相对于百分百查重的代码开发,产品设计重心和代码运行来说实在没有必要。

查重思想:关于查重我看了网上很多大佬的方法,但是总结起来不外乎:后缀表达式-》规范化二叉树-》遍历的方式,总而言之就是要将一定计算次序的表达式按照一定的规则和约束规范化成二叉树,在两两比较二叉树是否一致来判断表达式
是否重复,因为此处递归至底向上生成表达式的特殊性,故我对于每次递归时,参考博客四则运算-二叉树》,在拼接左右子树返回的子树时且当前符号为+或*时作出如下规约: 
1、左右子树的值不同,则值大的作为左子树
2、左右子树的值相同时,判断子树的运算符优先级大小,优先级大的作为左子树
3、运算符优先级相同,判断子树下的左子树值得大小,值大的作为左子树
4、若为子树为一个为数字,一个为表达式,则表达式作为左子树
5、比较左右树的左子树符号,优先级大的放左边
6、其余情况概率太低,不给予考虑。

代码:
 1             if (operate==1 or operate==3) and leftValue <=rightValue :
 2                 # 当右子树值大于左子树时
 3                 if leftValue<rightValue:
 4                     questionArray = [right['questionArray'], operate, left['questionArray']]
 5                 #     当左右子树值相等时
 6                 else:
 7                     # 当左右子树均为树时
 8                     if (type(left['questionArray']) == list) and (type(right['questionArray']) == list):
 9 
10                         # 当左子树运算符大于右子树运算符时
11                         if left['questionArray'][1]>right['questionArray'][1]:
12                             questionArray = [left['questionArray'], operate, right['questionArray']]
13 
14                         # 当左子树运算符小于右子树运算符时
15                         elif left['questionArray'][1]<right['questionArray'][1]:
16                             questionArray = [right['questionArray'], operate, left['questionArray']]
17 
18                         # 当左子树运算符等于右子树运算符时
19                         else:
20                             # 当左子树的左子树小于右子树的左子树时
21                             if left['questionArray'][0] < right['questionArray'][0]:
22                                 questionArray = [right['questionArray'], operate, left['questionArray']]
23 
24                             # 当左子树的左子树大于右子树的左子树时
25                             elif left['questionArray'][0] > right['questionArray'][0]:
26                                 questionArray = [left['questionArray'], operate, right['questionArray']]
27 
28                             # 当左子树的左子树等于右子树的左子树时
29                             else:
30                                 # 当左子树运算符小于右子树运算符
31                                 if left['questionArray'][2] < right['questionArray'][2]:
32                                     questionArray = [right['questionArray'], operate, left['questionArray']]
33 
34                                 # 其他情况因概率问题不给予考虑
35                                 else:
36                                     questionArray = [left['questionArray'], operate, right['questionArray']]
37 
38                     # 当仅由左子树为树时
39                     elif type(left['questionArray']) == list:
40                         questionArray = [left['questionArray'], operate, right['questionArray']]
41                     # 当仅由右子树为树时
42                     elif type(right['questionArray']) == list:
43                         questionArray = [right['questionArray'], operate, left['questionArray']]
44                     # 当左右子树均为数字,且已有左右子树值相等
45                     else:
46                         questionArray = [left['questionArray'], operate, right['questionArray']]
47             else:
48                 questionArray = [left['questionArray'], operate, right['questionArray']]


 

  

 

  

三、软件执行流程:

 

 

四、项目地址:https://git.coding.net/ojh496845051/sizeyunsuan.git

   目前项目已经移植到了Django上,项目地址:https://git.coding.net/ojh496845051/size.git

五、PSP:

 

 

 

posted @ 2018-03-30 14:34  黑丶夜行  阅读(1231)  评论(0)    收藏  举报