題目
(1)能自動生成國小四則運算題目;
(2)能支援任意分數的四則運算;
(3)能支援任意括号運算
思路
根據參數生成不定長度的表達式,以及能控制是否生成分數,能生成任意數量的中綴表達式,支援四則運算,括号運算以及分數運算
構造函數接口 def __init__(self, exps_num=10, num_l=1, num_r=10, exp_limit_len=10, has_fraction=True)
提供接口生成中綴表達式,傳回表達式資料集 def create_express(self)
提供接口将中綴表達式化為字尾表達式 def get_postfix(self, exp)
提供接口将字尾表達式進行計算并傳回結果 def cal_express(self, exp)
提供接口以使用者友好方式顯示中綴表達式 def get_showExp(self, exp)
源代碼
# -*- coding: utf-8 -*-
# author: 'boliang'
# date: 2018/4/18 21:04
import profile
import random
from fractions import Fraction
class Solution(object):
def __init__(self, exps_num=10, num_l=1, num_r=10, exp_limit_len=10, has_fraction=True):
self.__exps_num = exps_num
self.__has_fraction = has_fraction
self.__exp_limit_len = exp_limit_len
self.__num_l = num_l
self.__num_r = num_r
# 生成中綴表達式
def create_express(self):
exps = []
num = self.__exps_num
while num > 0:
num_len = random.randint(2, self.__exp_limit_len)
tmp_len = num_len - 1
exp = [self.__get_num(self.__has_fraction)]
while tmp_len > 0:
# 1為+,2為-,3為*,4為/
op_flag = random.randint(1, 4)
if op_flag == 1:
exp.append('+')
elif op_flag == 2:
exp.append('-')
elif op_flag == 3:
exp.append('*')
else:
exp.append('/')
exp.append(self.__get_num(self.__has_fraction))
tmp_len -= 1
brackets = random.randint(0, int(len(exp)/8))
while brackets > 0:
if self.__set_bracket(exp, num_len):
brackets -= 1
exps.append(exp)
num -= 1
return exps
def __set_bracket(self, exp, num_len):
index_a = 0
index_b = 0
while index_a == index_b:
rec = list(map(lambda x:random.randint(0, num_len-1), range(2)))
index_a = min(rec) + 1
index_b = max(rec) + 1
cal = 0
length = len(exp)
for i in range(length):
if type(exp[i]) != type('+'):
cal += 1
if cal == index_a:
if i+1 <= length and exp[i+1] == ')':
return False
exp.insert(i, '(')
cal = 0
for i in range(len(exp)):
if type(exp[i]) != type('+'):
cal += 1
if cal == index_b:
if i-1 >= 0 and exp[i-1] == '(':
return False
exp.insert(i+1, ')')
break
return True
# 生成一個數, 包括分數
def __get_num(self, has_fraction=True):
# 生成包括有分數
if has_fraction:
# 80%幾率為整數
flag = random.randint(1, 10)
if flag <= 8:
return self.__get_num(False)
else:
return Fraction(self.__get_num(False), self.__get_num(False))
# 生成整數
else:
return random.randint(self.__num_l, self.__num_r)
# 計算字尾表達式
def cal_express(self, exp):
record = []
for val in exp:
if type(val) == type('+'):
b = record.pop(-1)
a = record.pop(-1)
if val == '+':
record.append(a+b)
elif val == '-':
record.append(a-b)
elif val == '*':
record.append(a*b)
else:
record.append(a/b)
else:
record.append(val)
return record[0]
# 通過中綴表達式得到字尾表達式
def get_postfix(self, exp):
l_ops = {
'(': 1, '*': 5, '/': 5,
'+': 3, '-': 3, ')': 6
}
r_ops = {
'(': 6, '*': 4, '/': 4,
'+': 2, '-': 2, ')': 1
}
op_stack = []
post_stack = []
for val in exp:
if type(val) != type('+'):
post_stack.append(val)
elif len(op_stack) > 0:
while len(op_stack) > 0 and l_ops[op_stack[-1]] >= r_ops[val]:
if op_stack[-1] != '(' and op_stack[-1] != ')':
post_stack.append(op_stack.pop(-1))
else:
op_stack.pop(-1)
op_stack.append(val)
else:
op_stack.append(val)
while len(op_stack) > 0:
if op_stack[-1] != '(' and op_stack[-1] != ')':
post_stack.append(op_stack.pop(-1))
else:
op_stack.pop(-1)
return post_stack
def get_showExp(self, exp):
op = {'+': '+', '-': '-', '*': '×', '/': '÷', '(':'(', ')':')'}
jud_fun = lambda val: str(val) if type(val) != type('+') else op[val]
return ' '.join(map(jud_fun, exp))
# 測試函數
def test():
# 1. 測試程式自動生成10組表達式資料(包括分數和括号運算)
# 2. 測試通過中綴表達式計算得到字尾表達式
# 3. 根據字尾表達式計算結果(包括分數)
# 設定接口參數
# 表達式個數
express_num = 10
# 生成的數的下界
num_l = 1
# 生成的數的上界
num_r = 10
# 表達式的數字個數
exp_limit_len = 10
# 是否會生成分數
has_fraction = True
sol = Solution(express_num, num_l, num_r, exp_limit_len, has_fraction)
# 生成中綴表達式
exps = sol.create_express()
for ind, exp in enumerate(exps):
print('.......................................')
print('第{0}條表達式:{1}'.format(ind+1, exp))
tmp = sol.get_postfix(exp)
print('字尾表達式為:{0}'.format(tmp))
print('使用者界面中顯示的表達式:{0}'.format(sol.get_showExp(exp)))
print('運算結果為:{0}'.format(sol.cal_express(tmp)))
print('.......................................')
if __name__ == '__main__':
profile.run('test()')
根據單元測試,測試結果如下
效能分析, 運用Python profile庫
PSP表格
預計耗時(分鐘) | 是實際耗時(分鐘) | ||
Planning | 計劃 | 10 | |
Estimate | 估計這個任務需要多少時間 | 100 | |
Development | 開發 | 120 | 240 |
Analysis | 需求分析 | 5 | |
Design Spec | 生成設計文檔 | 3 | 23 |
Design Review | 設計複審(和同僚稽核設計文檔) | 2 | |
Coding Standerd | 代碼規範(為目前的開發制定合适的規範) | ||
Design | 具體設計 | ||
Coding | 具體編碼 | 30 | 60 |
Code Review | 代碼複審 | ||
Text | 測試(自測,修改代碼,送出修改) | ||
Reporting | 報告 | 20 | |
Text Report | 測試報告 | ||
Size Measurement | 計算工作量 | ||
Postmortem & Process Improvement Plan | 事後總結,并提出過程改進計劃 | ||
Sum | 合計 | 215 | 420 |