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

此作业要求参见:https://edu.cnblogs.com/campus/nenu/2018fall/homework/2148

此作业代码地址:https://git.coding.net/tianl364/Arithmetic_Demo.git

结对同学:田良

一.项目分析及编程收获

1. 功能一

要求:四则运算

支持出题4个数的四则运算题目,所有题目要求作者有能力正确回答 (提示:1/3 != 0.33333333333333333333333333333333,而是无限长)。

为了快出成果,你快速造个控制台的版本,包括以后改版成更优秀界面的核心功能,并考虑到扩展。

功能一重点

表达式生成,主要代码如下:

# 操作数4,运算符3
        for j in range(4 + 3):
            if j % 2 == 0:
                # 随机生成操作数
                exp.append(self.generate_operand())
            else:
                # 随机生成运算符
                exp.append(self.generate_operation())

操作数和运算符的随机生成,主要代码如下:

# 生成操作数
    def generate_operand(self):
        return str(random.randint(1, 9))

    # 生成运算符
    def generate_operation(self):
        operators = ['+', '-', '*', '/']
        return operators[random.randint(0, len(operators) - 1)]

功能一难点

中缀表达式转后缀表达式,主要代码如下:

# 将中缀表达式转换为后缀表达式
def middle_to_after(s):
    expression = []
    ops = []
    # ss = s.split(' ')
    # s = s.replace('=', '')
    for item in s:
        if item in ['+', '-', '*', '/']:
            while len(ops) >= 0:
                if len(ops) == 0:
                    ops.append(item)
                    break
                op = ops.pop()
                if op == '(' or ops_rule[item] > ops_rule[op]:
                    ops.append(op)
                    ops.append(item)
                    break
                else:
                    expression.append(op)
        elif item == '(':
            ops.append(item)
        elif item == ')':
            while len(ops) > 0:
                op = ops.pop()
                if op == '(':
                    break
                else:
                    expression.append(op)
        else:
            expression.append(item)

    while len(ops) > 0:
        expression.append(ops.pop())

    return expression

后缀表达式的计算,主要代码如下:

# 计算后缀表达式
def expression_to_value(expression):
    stack_value = []
    for item in expression:
        if item in ['+', '-', '*', '/']:
            n2 = stack_value.pop()
            n1 = stack_value.pop()
            result = cal(n1, n2, item)
            stack_value.append(result)
        else:
            stack_value.append(int(item))
    return stack_value[0]

# 四则运算规则
def cal(n1, n2, op):
    if op == '+':
        return n1 + n2
    if op == '-':
        return n1 - n2
    if op == '*':
        return n1 * n2
    if op == '/':
        return n1 / n2

功能一编程收获

在实现功能一的过程中,对之前数据结构里“栈”的使用较多,也花了许多时间复习这个概念以及中缀表达式与后缀表达式之间的转变,虽然之前使用过多次c语言版本的中缀转后缀,但这次通过python实现还是觉得非常便利。而在制定操作符优先级和四则运算规则时,通过不断封装函数来降低程序的耦合也使得程序更加易读。

2.功能二

要求:支持括号

老师看了你的表演,大大赞赏了你。然后她说,"你的题库里怎么都是没有括号的题呢,我记得你当初括号就掌握得不好啊。"你的脸红了,对老师说,"给我2个小时时间,我给你一个新版本,有括号的。"

功能二重点

括号的生成方式,主要代码如下:

if exp:
            i = 0
            for j in self.position_matrix[position]:
                # 0表示添加操作数和运算符
                if j == 0:
                    expression.append(exp[i])
                    if i < len(exp):
                        i += 1
                # -1表示添加左括号
                elif j == -1:
                    expression.append('(')
                # 1表示添加右括号
                elif j == 1:
                    expression.append(')')

功能二难点

括号的成对生成,主要代码如下:

# 4个数的式子括号最多两对,随机生成一对括号或两对括号
    position_matrix = [[-1, 0, 0, 0, 1, 0, 0, 0, 0, 2, 2],
                       [-1, 0, 0, 0, 0, 0, 1, 0, 0, 2, 2],
                       [0, 0, -1, 0, 0, 0, 1, 0, 0, 2, 2],
                       [0, 0, -1, 0, 0, 0, 0, 0, 1, 2, 2],
                       [0, 0, 0, 0, -1, 0, 0, 0, 1, 2, 2],
                       [-1, 0, 0, 0, 1, 0, -1, 0, 0, 0, 1],
                       [-1, -1, 0, 0, 0, 1, 0, 0, 1, 0, 0],
                       [-1, 0, 0, -1, 0, 0, 0, 1, 1, 0, 0],
                       [0, 0, -1, -1, 0, 0, 0, 1, 0, 0, 1],
                       [0, 0, -1, 0, 0, -1, 0, 0, 0, 1, 1]
                       ]

    # 生成括号表达式
    def generate_parentheses(self, exp):
        expression = []

        # 从10种情况中选取一种
        position = random.randint(0, 9)

功能二编程体会

括号的随机生成问题,单个括号通过位置也好实现,但是题目要求括号出现了嵌套的情况,这需要在每次添加操作数前都要随机插入括号,有时还需要插入2个左括号,而在插入左括号后还要随机插入右括号与之匹配,这些判断一一添加进去会十分冗余,经过我们的分析,先发现最多只能出现两对括号的情况,然后将所有括号一一列举,就发现这个数量并不庞大,通过枚举一个矩阵便可以轻松表示,随后我们又制定了矩阵的表示规则,较为简练的实现了功能二。

3.功能三

要求:限定题目数量,打印输出,避免重复

功能三重点

对输入指令的判断,主要代码如下:

# 这是主方法
def main(argv):
    if '-c' in sys.argv:
        input_text = str(sys.argv[2])
        if input_text.isdigit() and int(input_text) > 0:
            normalize_exp(int(input_text))
        else:
            print('题目数量必须是 正整数。')
    else:
        circular_problem()


if __name__ == '__main__':
    main(sys.argv[1:])

按指定格式输出,主要代码如下:

# 规范输出
def normalize_exp(num):
    i = 0
    while i < num:
        generate = Exp_Generating.Generator()
        inputText = generate.generate()
        expression = middle_to_after(inputText)
        value = expression_to_value(expression)
        inputText += '='
        print('%-15s %-15s' % (inputText, value))
        i += 1

功能三难点

输入题目个数的校验,主要代码如下:

      input_text = str(sys.argv[2])
         if input_text.isdigit() and int(input_text) > 0:
             normalize_exp(int(input_text))
         else:
             print('题目数量必须是 正整数。')

功能三编程体会

这个查重的逻辑表面上看起来较为复杂,但是我们可以通过利用数据结构中二叉树的原理进行实现,先将表达式转化为二叉树,再将二叉树进行后序遍历,如果两个式子通过交换律能变成一样的式子,那么他们所生产的二叉树后序遍历的结果也一样。

二.结对编程的体会

由于自身基础和编程能力较差,对于我来说结对编程是一个向我结对伙伴田良学习的过程。可以看到别人的思路和技能,得到实时的讲解,受到激励,从而努力提高自己的水平,提出更多创意。在结对编程中,因为能够随时的交流,我在程序中的错误也减少了许多,也学会了从对方的角度看待问题,去更好的解决程序开发过程中遇到的各种问题。

三.花费时间较长的事件

1 中缀表达式如何转成后缀表达式

2 类名,函数名,变量名如何命名规范

3 对于添加括号问题时是选用枚举还是随机

4 是否在一个文件中完成所有功能

5 由于自己编程能力较差,导致自己的任务未能及时完成造成整体工程拖延

四.给出照片1张,包括结对的2位同学、工作地点、计算机,可选项包括其他能表达结对编程工作经历的物品或场景。

工作地点:信息科学与技术学院 数据可视化与可视分析实验室,使用田良的电脑进行编程

原文地址:https://www.cnblogs.com/nenusoft/p/9755242.html