《编程珠玑》习题练习In Python——第三章 数据决定程序结构
2016-12-03 17:05
701 查看
本章的主旨是:数据视图决定了程序结构。简单的数据表示可以使用简单高效的程序来处理。好的数据表示是好的程序的前提。正如好的食物原料是做出美味食物的前提。
本章中的编程思路总结:
1、尽量使用数组处理重复数据。
2、定义简单的表示语言和一个语言的解释器来表示复杂的数据结构。
代码如下:
an=c1an−1+c2an−2+...+ckan−k+ck+1
其中c为常数。编写一个程序,输入为k,a1,a2,...ak,c1,c2...ck+1和m,输出为a1到am。
著名的斐波那契数列其实就是这个级数在k=2的时候的一种特殊形式。斐波那契数列使用递归法计算时间复杂度是指数级别的。具体证明要用到母函数的方法。总之,递归法不能解决这个问题,那么可以从序号更小的元素开始依次计算,每次计算出的值存储在数组中。每计算一个元素,只需要用到比它小的k个元素,因此更进一步,可以只保存这k个数。实现代码:
非常清楚记得大一学C++就有做过这种题目。要求输入一个菱形或者三角形。当时整个程序写了大量的输出代码,根据每行输出有规律的变化可以使用一些循环简化代码。这样做的问题在于,将数据内容编码在了程序之中。也就是说,程序只能输出菱形,如果要输出三角形,整个代码都需要修改。
这个题更进一步,要根据输入来输出不同的图形。现在就不可能为每个字母写一个子程序了。根据数据和程序分离的思想。应该将图形表示为一种简单的数据形式,将这种数据输入一个绘制程序应该要可以获得不同的图形。这就是定义一种描述语言同时实现该语言的解释器的编程方法。
首先定义一种描述图形的语言,结构如:
那么如字母I可以表示为:
实现这个语言的解释器:
测试程序:
这个描述语言的能力有限,描述复杂图形是及其复杂的。但是在绘制字母任务中勉强可以胜任。合理的设计应该在功能和复杂度上取得平衡。
第一个问题是后面两个问题的基础。我的计算方法用一张图表示如下:
这里要计算2017年某天到2020年某天的天数差X。只需要分别计算两个时间点在该年中的天数A,B,以及两个时间点年份区间的天数和Y。X = Y+B-A。需要判断两个天数的先后。程序分为几个部分,首先是对时间字符串的解释程序:
计算二月的天数:
计算时间是一年中的第几天:
计算一年总共几天:
最后计算天数差就很好算了:
第二个问题,计算星期。在第一个问题基础上,只要知道某一天的星期,就可以通过天数差来推算其他任意一天的星期了。不过上一问返回非负数,这一问里面需要增加这个时间差的正负。将写这段代码的时间2016年12月3日星期6作为基准,得到代码:
第三问实现没有问题,但是还是应该遵循一个原则,尽量使用循环,增加灵活性减少程序复杂度:
2016年12月显示如下:
哈哈,好漂亮。
我理解的题目意思就是这么简单,答案考虑翻转字符什么我觉得完全没必要。代码:
首先要定义文本模板的格式,使用
测试代码:
输出:
本章中的编程思路总结:
1、尽量使用数组处理重复数据。
2、定义简单的表示语言和一个语言的解释器来表示复杂的数据结构。
习题1
税收计算。准确说是超额累进税率计算。使用两个数组分别定义不同等级税收的区间,和该区间的税率。一个循环便可解决问题。最后一个区间的上限应该设置为无穷,Python可以使用float('inf')来表示。
代码如下:
def test_1(): tax_strt = [2000,3000,4000,6000,float('inf')] tax_rate = [0.14,0.17,0.24,0.40] income = 20000 tax = 0 for i in range(len(tax_strt)-1): if income < tax_strt[i]: break tax += (min(income-tax_strt[i],tax_strt[i+1]-tax_strt[i]))*tax_rate[i] print(tax)
习题2
k阶常系数线性递归定义的级数如下:an=c1an−1+c2an−2+...+ckan−k+ck+1
其中c为常数。编写一个程序,输入为k,a1,a2,...ak,c1,c2...ck+1和m,输出为a1到am。
著名的斐波那契数列其实就是这个级数在k=2的时候的一种特殊形式。斐波那契数列使用递归法计算时间复杂度是指数级别的。具体证明要用到母函数的方法。总之,递归法不能解决这个问题,那么可以从序号更小的元素开始依次计算,每次计算出的值存储在数组中。每计算一个元素,只需要用到比它小的k个元素,因此更进一步,可以只保存这k个数。实现代码:
def test_2(): k = 5 m = 6 c = list(range(1,k+2)) a = list(range(1,k+1)) curIndex = k cur = 0 while(curIndex<m): cur = 0 for i in range(0,k): cur += c[i]*a[(curIndex+i)%k] cur += c[-1] a[curIndex%k] = cur curIndex +=1 print(cur)
习题3
编写一个函数,输入为一个大写字母,输出为一个数组,该数组用图形化的形式表示该字母。非常清楚记得大一学C++就有做过这种题目。要求输入一个菱形或者三角形。当时整个程序写了大量的输出代码,根据每行输出有规律的变化可以使用一些循环简化代码。这样做的问题在于,将数据内容编码在了程序之中。也就是说,程序只能输出菱形,如果要输出三角形,整个代码都需要修改。
这个题更进一步,要根据输入来输出不同的图形。现在就不可能为每个字母写一个子程序了。根据数据和程序分离的思想。应该将图形表示为一种简单的数据形式,将这种数据输入一个绘制程序应该要可以获得不同的图形。这就是定义一种描述语言同时实现该语言的解释器的编程方法。
首先定义一种描述图形的语言,结构如:
r3s3#3s3。有三种特殊符号,r代表行重复,s代表空格,空格忽略,其他符号则代表该符号本身。除了r之外,符号后面接数字代表该符号在一行中重复的次数,r符号则表示该行重复的次数。数字均是一位数。上面的语句输出为:
### ### ###
那么如字母I可以表示为:
l2#6 l4s2#2s2 l2#6,输出为:
###### ###### ## ## ## ## ###### ######
实现这个语言的解释器:
def InterpretLetter(dsc): cur = 0 pic = [] while(cur<len(dsc)): cur+=1 r = int(dsc[cur]) cur+=1 line = [] while(cur<len(dsc) and dsc[cur]!='l'): char = dsc[cur] if char ==' ': cur+=1 continue elif char =='s': char = ' ' cur +=1 time = int(dsc[cur]) line += [char]*time cur +=1 for i in range(r): pic.append(line) return pic
测试程序:
def test_3(): dic ={ 'C': "l2#6 l4#2 l2#6", 'E':"l2#7 l2#2 l2#7 l2#2 l2#7", 'H':"l4#2s3#2 l2#7 l4#2s3#2", "I":"l2#6 l4s2#2s2 l2#6" } letter = "I" pic = InterpretLetter(dic[letter]) for l in pic: print("".join(l))
这个描述语言的能力有限,描述复杂图形是及其复杂的。但是在绘制字母任务中勉强可以胜任。合理的设计应该在功能和复杂度上取得平衡。
习题4
编写日期处理函数,处理以下问题:给定两个日期,计算两者天数差;给定一个日期,返回星期;给出年月,使用字符数组生成该月日历。第一个问题是后面两个问题的基础。我的计算方法用一张图表示如下:
这里要计算2017年某天到2020年某天的天数差X。只需要分别计算两个时间点在该年中的天数A,B,以及两个时间点年份区间的天数和Y。X = Y+B-A。需要判断两个天数的先后。程序分为几个部分,首先是对时间字符串的解释程序:
def InterpDate(ds):# 解释日期字符串 date = [0,0,0] # 年月日 dInd = 0 sInd = 0 while(sInd<len(ds)): v = ds[sInd] sInd += 1 if v == '/': dInd +=1 if dInd >= len(date): raise Exception("date error") else: v = int(v) date[dInd] = date[dInd]*10 + v return date
计算二月的天数:
def GetFebDay(year): if year%4 ==0 and year % 100 != 0 or year%400 ==0: return 29 else: return 28
计算时间是一年中的第几天:
MONTH_DAY = [31,0,31,30,31,30,31,31,30,31,30,31] def DaysPassInYear(date):# 计算当年过去几天 day = 0 day += sum(MONTH_DAY[:(date[1]-1)]) # 过去的月 if date[1]>2: day += GetFebDay(date[0]) # 本月过去的日 day += date[2] return day
计算一年总共几天:
def DaysInYear(year):# 计算一年几天 return sum(MONTH_DAY)+GetFebDay(year)
最后计算天数差就很好算了:
def CmpDate(d1,d2): # 比较d1 d2 两个日期 if d1[0] * 10 ** 4 + d1[1] * 10 ** 2 + d1[2] < d2[0] * 10 ** 4 + d2[1] * 10 ** 2 + d2[2]: return -1 if d1[0] * 10 ** 4 + d1[1] * 10 ** 2 + d1[2] > d2[0] * 10 ** 4 + d2[1] * 10 ** 2 + d2[2]: return 1 else: return 0 def CalDay(ds1,ds2): # 计算两日期间的天数差。输入字符串 d1,d2 = InterpDate(ds1),InterpDate(ds2) if CmpDate(d1,d2) < 0: #保证 d1更大 tmp = d1 d1 = d2 d2 = tmp day1 = DaysPassInYear(d1) day2 = DaysPassInYear(d2) dayYear = 0 for y in range(d2[0],d1[0]): dayYear+=DaysInYear(y) return dayYear+day1-day2
第二个问题,计算星期。在第一个问题基础上,只要知道某一天的星期,就可以通过天数差来推算其他任意一天的星期了。不过上一问返回非负数,这一问里面需要增加这个时间差的正负。将写这段代码的时间2016年12月3日星期6作为基准,得到代码:
def GetWeek(ds): # 给定日期,计算星期。输入字符串 day = CalDay(ds,STD_DS) if CmpDate(InterpDate(ds),InterpDate(STD_DS)) < 0: day = day*-1 return (day+STD_WEEK)%7
第三问实现没有问题,但是还是应该遵循一个原则,尽量使用循环,增加灵活性减少程序复杂度:
def GetCalend(year,month): # 给年月,输出日历 cal =[] cal.append("Year: "+str(year) +" Month: " + str(month)) line = [] for w in WEEKS: line.append(w) line.append("\t") cal.append(line) line =[] wk = GetWeek(''.join([str(year),'/',str(month),'/1'])) line += ["\t"]*wk day = 1 md = MONTH_DAY[month-1] if month ==2: md = GetFebDay(year) while(day <= md): line+= [str(day)]+["\t"] day+=1 wk = (wk+1)%7 if wk == 0: cal.append(line) line = [] if len(line)>0: cal.append(line) return cal
2016年12月显示如下:
Year: 2016 Month: 12 Sun Mon Tue Wen Thu Fri Sat 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
哈哈,好漂亮。
习题5
给一个单词和后缀列表。匹配该单词的后缀。我理解的题目意思就是这么简单,答案考虑翻转字符什么我觉得完全没必要。代码:
def test_5(): SUFFIXS = ['et-ic','al-is-tic','s-tic','p-tic'] word = "ppap-tic" s = None for suf in SUFFIXS: strt = len(word)-len(suf) find = True for i in range(len(suf)): if word[strt+i] != suf[i]: find = False break if find: s = suf break print(word,s)
习题6
编写一个格式信件发生器。也就是给定一个文本模板和文本变量,自动将变量填充到模板中。Python中可以直接用format函数实现。不过这里我们要自己实现这个功能。首先要定义文本模板的格式,使用
$加一个序号n表示第n变量。
$和序号必须相连。另外定义
\为转义字符。代码如下:
def InterpretText(ts,args): t = [] cur = 0 getArg = False argNum = 0 escape = False while(cur<len(ts)): c = ts[cur] if getArg: if ord(c) in range(ord('0'),ord('9')+1): argNum = argNum*10 + ord(c)-ord('0') else: t.append(args[argNum]) t.append(c) argNum = 0 getArg = False elif escape: t.append(c) escape = False elif c == '\\': escape = True elif c == "$": getArg = True else: t.append(c) cur+=1 return ''.join(t)
测试代码:
def test_6(): ts = r"Hello \$ $0 \\ !" text = InterpretText(ts,["World"]) print(text)
输出:
Hello $ World \ !
相关文章推荐
- 编程珠玑:第三章 数据决定程序结构 习题解答
- 《编程珠玑》--第三章 数据决定程序结构
- 【编程珠玑】读书笔记 第三章 数据决定程序结构
- 第三章 数据决定程序结构
- 【编程珠玑】第三章 数据决定程序结构
- 《编程珠玑》习题练习In Python——第二章 啊哈!算法
- 《编程珠玑》习题练习In Python——第一章 开篇
- 3、编程珠玑笔记三数据决定程序结构
- learning python in the hard way习题1~5的附加题练习
- Python程序设计基础 数据结构与算法习题
- 元宵节后第一发(数据决定程序结构)
- 数据结构——c语言描述 第三章 (2)栈的练习(四则运算的实现)
- python3 第三章 - 程序的基本结构
- (3)数据决定程序结构
- 本方法学python 习题24(综合练习) 习题25(更多关于函数和变量的练习)习题26(修改程序)
- 数据结构与算法(c语言) 学习笔记——第三章练习
- 【廖雪峰python3.0】-课后习题:第2章:第一个python程序 and 第三章:python基础
- 数据决定程序结构
- 《编程珠玑》阅读小记(3) — 数据决定数据结构
- 《编程珠玑》阅读小记(3) — 数据决定数据结构