四则运算题目项目笔记

    四则运算题目项目笔记


 

PSP表格记录的估计将在程序的各个模块的开发上耗费的时间


 

PSP2.1

Personal Software Process Stages

Time

Planning

计划

 

  · Estimate

  · 估计这个任务需要多少时间

 24h

Development

开发

 

  · Analysis

  · 需求分析 (包括学习新技术)

 2h

  · Design Spec

  · 生成设计文档

 1h

  · Design Review

  · 设计复审 (和同事审核设计文档)

 1h

  · Coding Standard

  · 代码规范 (为目前的开发制定合适的规范)

 1h

  · Design

  · 具体设计

 1h

  · Coding

  · 具体编码

 12h

  · Code Review

  · 代码复审

 1h

  · Test

  · 测试(自我测试,修改代码,提交修改)

 1h

Reporting

报告

 

  · Test Report

  · 测试报告

 1h

  · Size Measurement

  · 计算工作量

 30min

  · Postmortem & Process Improvement Plan

  · 事后总结, 并提出过程改进计划

 30min

 

合计

 22h

 

 

  需求分析 


1. 使用 -n 参数控制生成题目的个数, 使用 -r 参数控制题目中数值(自然数、真分数和真分数分母)的范围。

3. 生成的题目中计算过程不能产生负数,也就是说算术表达式中如果存在形如e1 − e2的子表达式,那么e1 ≥ e2

4. 生成的题目中如果存在形如e1 ÷ e2的子表达式,那么其结果应是真分数

5. 每道题目中出现的运算符个数不超过3个。

6. 程序一次运行生成的题目不能重复,即任何两道题目不能通过有限次交换+和×左右的算术表达式变换为同一道题目。例如,23 + 45 = 和45 + 23 = 是重复的题目,6 × 8 = 和8 × 6 = 也是重复的题目。3+(2+1)和1+2+3这两个题目是重复的,由于+是左结合的,1+2+3等价于(1+2)+3,也就是3+(1+2),也就是3+(2+1)。但是1+2+3和3+2+1是不重复的两道题,因为1+2+3等价于(1+2)+3,而3+2+1等价于(3+2)+1,它们之间不能通过有限次交换变成同一个题目。

生成的题目存入执行程序的当前目录下的Exercises.txt文件。

其中真分数在输入输出时采用如下格式,真分数五分之三表示为3/5,真分数二又八分之三表示为2’3/8。

7. 在生成题目的同时,计算出所有题目的答案,并存入执行程序的当前目录下的Answers.txt文件。

8. 程序应能支持一万道题目的生成。

9. 程序支持对给定的题目文件和答案文件,判定答案中的对错并进行数量统计,并将统计结果输出到文件Grade.txt。

 

 

  思路及设计


 •树的同构

   判断表达式是否为统一表达式的算法,可用树的同构问题解决,虽然在我的程序里,因为时间关系没有考虑到这个方法,但是这不失为解决问题的一个好的方法。根据网上找的一些资料,当树为无根树时,可以枚举每一的树的节点作为根,然后判相应的有根树的同构了。

解法1:暴力枚举,就是对于两棵树,递归的比较两个数的子树,如果存在两个树的子树之间的某一个一一配对,使所有相应的子树都同构,那么这两棵树同构。

解法2:hash,算法描述见07年国家集训队论文-杨弋《Hash在信息学竞赛中的一类应用》。

 

 •中缀转后缀

   中缀转后缀解法利用了栈。目的是将中缀表达式(即标准形式的表达式)转换为后缀式。例如:a+b*c+(d*e+f)*g转换成abc*+de*f+g*+

   转换原则:

1.当读到一个操作数时,立即将它放到输出中。操作符则不立即输出,放入栈中。遇到左圆括号也推入栈中。

2.如果遇到一个右括号,那么就将栈元素弹出,将符号写出直到遇到一个对应的左括号。但是这个左括号只被弹出,并不输出。

3.在读到操作符时,如果此时栈顶操作符优先性大于或等于此操作符,弹出栈顶操作符直到发现优先级更低的元素位置。除了处理)的时候,否则决不从栈中移走"("。操作符中,+-优先级最低,()优先级最高。

4.如果读到输入的末尾,将栈元素弹出直到该栈变成空栈,将符号写到输出中。

 

解如下:

首先,读入a,并送到输出,然后+被读入并压入栈中。接下来b读入并送到输出,此时状态如下:

stack:                                        输出:a b

           +

back  top

接下来读入*,由于优先性比栈顶元素+大(原则3),因此被压入栈顶,接着读入c,并送到输出:

stack:                                      输出:a b c

        + *

back top

然后读入+,由于此时栈顶元素为*,优先级比+大,因此将*弹出,弹出后原来的+变成栈顶元素,由于+的优先性和当前读入的+优先性相等,因此也被弹出(原则3),最后将读入的+压入栈中。因此此时状态如下:

stack:                                       输出:a b c * +

            +

back  top

下一个读入的符号是(,由于具有最高优先级,因此将其放入栈中,然后读入d:

stack:                                       输出:a b c * + d

             + (

back     top

继续读入,此时读入*,除非处理),否则(决不弹出(原则3),因此*被压入栈中,接下来读入e,并送到输出:

stack:                                      输出:a b c * + d e

             + ( *

back        top

再往后读入的符号是+,将*弹出并输出。(原则3,与之前步骤相似),然后将+压入栈中,接着读入f并送到输出:

stack:                               输出:a b c * + d e * f

           + ( +

back       top

现在读入),因此弹出栈元素直到遇到“(”(原则2):

stack:                                输出: a b c * + d e * f +

            +

back  top

下面又读入一个*,被压入栈中,然后读入g并输出:

stack:                                    输出: a b c * + d e * f + g

          + *

back   top

现在输入为空,弹出栈中所有元素:

stack :                                    输出: a b c * + d e * f + g * +

empty                                 

自此全部完成。(总结自数据结构与算法导论C++版第三版)

 

 •四则运算的计算过程

   在具体实现过程中,需要设置一个堆栈,用来保存已经读到的对象。换句话说,从左到右依次扫描后缀表达式,当读得地一个单词若为运算对象,就将其压入堆栈,;当读得的一个单词若为运算符,就从堆栈中取出相应的运算对象施以该运算符所代表的操作,并将运算结果作为一个新的运算对象压入堆栈,表达式最后的计算结果就位于栈顶指针top所指的位置上。

 

 

 

   感想与总结


 

  这次的项目花了我很多的时间去完成,困难挺多的。由于是第一次写C++的程序,需要做很多前期的准备工作, 其次,对于判断表达式是否相同的问题,写的时候并没有想到一个理想的方法,这就导致我的代码冗长复杂,也增大了调试的难度。这个经历让我知道了基础的重要性,很多知识点都是来自数据结构。总的来说,这次的收获不少,希望下次能写得更好吧。

 

 

   测试用例


对于题目的生成器:

•n=10   r=10

•Exercises.txt

1. ( 8 - 2 ) + 5 =
2. ( 6/4 - 1/2 ) - 1 =
3. 9/7 × 2/9 =
4. 1 ÷ 2 - 0 =
5. 0 × 2 =
6. 5 × 0 - 0 =
7. 6 - 1 =
8. 6 ÷ 3 - 2 =
9. 8 - 4 =
10. 3 × 6 =

•Answers.txt

1. 11
2. 0/8
3. 18/63
4. 1/2
5. 0
6. 0
7. 5
8. 0
9. 4
10. 18

 

•n=5   r=10

•Exercises.txt

1. ( 4 - 3 ) × 4 =
2. ( 1/2 - 0/2 ) + 1 =
3. 2 - 2 =
4. 0 × 2 =
5. 4/2 × 2/4 =

•Answers.txt

1. 4
2. 1'2/4
3. 0
4. 0
5. 1'0/8

 

•n=10   r=10

•Exercises.txt

1. 0/4 × 9/8 =
2. ( 5 + 5 ) - 1/1 =
3. 5 + 2 + 7 + 6 =
4. ( 2 + 1 ) + 8 =
5. 1/9 × 8/2 =
6. 4/1 ÷ 3/2 - 1 =
7. 7 + 4 =
8. ( 9 - 3 ) - 6 =
9. 8 × 6 =
10. 8 + 6 =

•Answers.txt

1. 0/32
2. 9'0/1
3. 20
4. 11
5. 8/18
6. 5/3
7. 11
8. 0
9. 48
10. 14

 

•a.txt

1. 2 + ( 3 - 10 / 5 ) * 4 =
2. 5 + ( 6 - 3 ) * 1 =
3. ( 3 + 1 ) / 2 =
4. 5 / 2 + 3 =

•b.txt

1. 0
2. 0
3. 0
4. 0

•Grades.txt

Correct: 0

Wrong: 4 (1, 2, 3, 4)

 

•a.txt

1. 2 + ( 3 - 10 / 5 ) * 4 =
2. 5 + ( 6 - 3 ) * 1 =
3. ( 3 + 1 ) / 2 =
4. 5 / 2 + 3 =

•b.txt

1. 0
2. 8
3. 2
4. 11/2

•Grades.txt

Correct: 3 (2, 3, 4)
Wrong: 1 (1)

 

•a.txt

1. 2 + ( 3 - 10 / 5 ) * 4 =
2. 5 + ( 6 - 3 ) * 1 =
3. ( 3 + 1 ) / 2 =
4. 5 / 2 + 3 =

•b.txt

1. 0
2. 8
3. 0
4. 11/2

•Grades.txt

Correct: 2 (2, 4)
Wrong: 2 (1, 3)

 

•a.txt

1. 2 + ( 3 - 10 / 5 ) * 4 =
2. 5 + ( 6 - 3 ) * 1 =
3. ( 3 + 1 ) / 2 =
4. 5 / 2 + 3 =

•b.txt

1. 0
2. 0
3. 0
4. 11/2

•Grades.txt

Correct: 1 (2)
Wrong: 3 (1, 2, 3)

 

•a.txt

1. 2 + ( 3 - 10 / 5 ) * 4 =
2. 5 + ( 6 - 3 ) * 1 =
3. ( 3 + 1 ) / 2 =
4. 5 / 2 + 3 =

•b.txt

1. 6
2. 8
3. 2
4. 11/2

•Grades.txt

Correct: 4 (1, 2, 3, 4)
Wrong: 0

 

•a.txt

1. 2 + ( 3 - 10 / 5 ) * 4 =
2. 5 + ( 6 - 3 ) * 1 =
3. ( 3 + 1 ) / 2 =
4. 5 / 2 + 3 =

•b.txt

1. 0
2. 8
3. 0
4. 11/2

•Grades.txt

Correct: 2 (1, 3)
Wrong: 2 (2, 4)

 

•a.txt

1. 2 + ( 3 - 10 / 5 ) * 4 =
2. 5 + ( 6 - 3 ) * 1 =
3. ( 3 + 1 ) / 2 =
4. 5 / 2 + 3 =

•b.txt

1. 6
2. 0
3. 0
4. 11/2

•Grades.txt

Correct: 2 (1, 4)
Wrong: 2 (2, 3)

posted on 2015-09-22 19:44  Yuccalan  阅读(268)  评论(1编辑  收藏  举报