import random
import timeit
from turtle import *
import turtle
from pythonds import Stack
以下均为函数或类,主函数调用实现。
本人手写或借阅资料,仅供参考,有错误欢迎指正。
#4.1 写一个递归函数来计算数的阶乘
def myFactorial(n):
if n <= 0:
return 'Error'
if n == 1:
return 1
else:
return n * myFactorial(n - 1)
#4.2 写一个递归函数来反转列表
rl = []
def reverseList(l, idx):
global rl
if idx >= len(l):
return
else:
reverseList(l, idx + 1)
rl.append(l[idx])
def reverseListtest():
mrl = [1, 2, 3, 4, 5]
reverseList(mrl, 0)
print(rl)
#递归: 分形树
#4.3 采用下列一个或全部方法修改递归树程序
#修改树枝的粗细程度,使得branchLen 越小,线条越细。
#修改树枝的颜色,使得当branchLen 非常小时,树枝看上去像叶子。
#修改小乌龟的转向角度,使得每一个分支的角度都是一定范围内的随机值,例如使角度取值范围是15~45 度
#递归地修改branchLen,使其减去一定范围内的随机值,而不是固定值。
def tree(branchLen, t):
if branchLen > 5:
t.width(10 * branchLen / 110)
if branchLen < 30 :
t.color('green')
else:
t.color('brown')
t.forward(branchLen)
r = random.randrange(15, 30)
l = random.randrange(30, 45)
branchLen1 = random.randrange(10, 30)
branchLen2 = random.randrange(10, 30)
t.right(r)
tree(branchLen - branchLen1, t)
t.left(l)
tree(branchLen - branchLen2, t)
t.right(l - r)
if branchLen < 30 :
t.color('green')
else:
t.color('brown')
t.backward(branchLen)
def treetest():
t = Turtle()
myWin = t.getscreen()
t.left(90)
t.up()
t.backward(300)
t.down()
tree(110, t)
myWin.exitonclick()
#谢尔平斯基三角形
#4.4 找到一种绘制分形山的算法。提示:可以使用三角形
def drawTriangle(points, color, myTurtle):
myTurtle.fillcolor(color)
myTurtle.up()
myTurtle.goto(points[0])
myTurtle.down()
myTurtle.begin_fill()
myTurtle.goto(points[1])
myTurtle.goto(points[2])
#myTurtle.goto(points[0])
myTurtle.end_fill()
def getmid(p1, p2):
return ((p1[0] + p2[0]) / 2, (p1[1] + p2[1]) / 2)
def sierpinski(points, degree, myTurtle):
colormap = ['blue', 'red', 'green', 'white', 'yellow', 'violet', 'orange']
drawTriangle(points, colormap[degree], myTurtle)
if degree > 0:
sierpinski([points[0], getmid(points[0], points[1]), getmid(points[0], points[2])],
degree - 1, myTurtle)
sierpinski([points[1], getmid(points[1], points[0]), getmid(points[1], points[2])],
degree - 1, myTurtle)
sierpinski([points[2], getmid(points[2], points[1]), getmid(points[2], points[0])],
degree - 1, myTurtle)
def sierpinskitest():
myTurtle = Turtle()
myWin = myTurtle.getscreen()
myPoints = [(-500, -250), (0, 500), (500, -250)]
sierpinski(myPoints, 5, myTurtle)
myWin.exitonclick()
def mountain(myTurtle, points, depth, color):
y_offset = random.randrange(10, 40)
midpoint = ((points[0][0] + points[1][0]) / 2, (points[1][1] + points[1][1]) / 2 + y_offset)
drawTriangle([points[0], points[1], midpoint], color, myTurtle)
if depth > 0:
mountain(myTurtle, [points[0], midpoint], depth - 1, color)
mountain(myTurtle, [midpoint, points[1]], depth - 1, color)
def mountaintest():
myTurtle = Turtle()
myWin = myTurtle.getscreen()
colormap = ['#DAE0DF','#959998','#505453','#070707']
for i in range(4):
points = [(-400, -50 - 30 * i), (400, -50 - 30 * i)]
mountain(myTurtle, points, 6, colormap[i])
myWin.exitonclick()
#4.5 写一个递归函数来计算斐波那契数列,并对比递归函数与循环函数的性能。
def calFibonaccirecursion1(n):
if n < 3:
return 1
else:
return calFibonaccirecursion1(n - 1) + calFibonaccirecursion1(n - 2)
tmp = []
def calFibonaccirecursion2(n):
if n < 3:
return 1
if tmp[n] == 0:
tmp[n] = calFibonaccirecursion2(n - 1) + calFibonaccirecursion2(n - 2)
return tmp[n]
def usecalFibonaccirecursion2(n):
global tmp
tmp = [0] * (n + 1)
return calFibonaccirecursion2(n)
def iteaFibonacci(n):
if n < 3:
return 1
res, pre, cur = 0, 1, 1
for _ in range(n - 2):
res = pre + cur
pre = cur
cur = res
return res
# 在循环的次数较大的时候,迭代的效率明显高于递归
def performantFibonacci():
for i in range(40, 60):
t = timeit.Timer("usecalFibonaccirecursion2(%d)" % i,
"from __main__ import usecalFibonaccirecursion2")
recursion_time = t.timeit(number = 1000)
t = timeit.Timer("iteaFibonacci(%d)" % i, "from __main__ import iteaFibonacci")
itea_time = t.timeit(number = 1000)
print("%d, %10.3f, %10.3f" % (i, recursion_time, itea_time))
#递归: 汉诺塔问题
#4.6 实现汉诺塔问题的一个解决方案,使用3 个栈来记录盘子的位置。
#4.12 利用turtle 绘图模块修改汉诺塔程序,将盘子的移动过程可视化。提示:可以创建多
#只小乌龟,并将它们的形状改为长方形。
def moveTower(plates, poles, height, fromPole, toPole, withPole):
if height >= 1:
moveTower(plates, poles, height - 1, fromPole, withPole, toPole)
moveDisk(plates, poles, fromPole, toPole)
moveTower(plates, poles, height - 1, withPole, toPole, fromPole)
def moveDisk(plates, poles, fp, tp):
mov = poles[fp].peek()
plates[mov].goto((fp - 1) * 400, 300)
plates[mov].goto((tp - 1) * 400, 300)
l=poles[tp].size()
plates[mov].goto((tp - 1) * 400,-90 + 20 * l)
poles[tp].push(poles[fp].pop())
print("moveing disk from %d to %d\n" % (fp, tp))
def drawpoles():
myTurtle = Turtle()
myTurtle.hideturtle()
def drawpole(i):
myTurtle.up()
myTurtle.pensize(10)
myTurtle.speed(100)
myTurtle.goto(400 * (i - 1), 300)
myTurtle.down()
myTurtle.goto(400 * (i - 1), -100)
myTurtle.goto(400 * (i - 1) - 20, -100)
myTurtle.goto(400 * (i - 1) + 20, -100)
drawpole(0)
drawpole(1)
drawpole(2)
def create_plates(n):
plates = [Turtle() for _ in range(n)]
for i in range(n):
plates[i].up()
plates[i].hideturtle()
plates[i].shape('square')
plates[i].shapesize(1, 20 -i)
plates[i].goto(-400,-90+20*i)
plates[i].showturtle()
return plates
def polestack():
return [Stack() for _ in range(3)]
def moveTowertest():
myWin = turtle.Screen()
drawpoles()
n=int(input("请输入汉诺塔的层数并回车确定:\n"))
plates = create_plates(n)
poles = polestack()
for i in range(n):
poles[0].push(i)
moveTower(plates, poles, n, 0, 2, 1)
myWin.exitonclick()
#4.7 使用turtle 绘图模块写一个递归程序,画出希尔伯特曲线。
def turn_direction(myTurtle, d):
if d == 1:
myTurtle.right(90)
elif d == -1:
myTurtle.left(90)
#每第三次前进的前后需要转向
#使用类是为了不共享direction值
class Direct():
direction = 1
count = 1
length = 12
def direct3(self, myTurtle):
turn_direction(myTurtle, self.direction)
myTurtle.forward(self.length)
turn_direction(myTurtle, self.direction)
if self.count % 2 == 1:
self.direction *= -1
self.count += 1
direct_list = []
def helbert(myTurtle, depth):
length = 12
for i in range(1, 10):
if depth > 1:
helbert(myTurtle, depth - 1)
if i % 3 == 0 and i != 9:
direct_list[depth - 1].direct3(myTurtle)
elif i == 9:
break
else:
myTurtle.forward(length)
def drawhelbert():
myTurtle = Turtle()
myTurtle.left(90)
myWin = myTurtle.getscreen()
depth = 3
for _ in range(depth):
direct_list.append(Direct())
helbert(myTurtle, depth)
myWin.exitonclick()
#4.8 使用turtle 绘图模块写一个递归程序,画出科赫雪花。
def koch(myTurtle, len, n):
if n == 0:
myTurtle.fd(len)
else:
for i in [0, 60, -120, 60]:
myTurtle.left(i)
koch(myTurtle, len/3, n - 1)
def drwakoch():
myTurtle = Turtle()
myWin = myTurtle.getscreen()
length = 500
level = 3
koch(myTurtle, length, level)
myTurtle.right(120)
koch(myTurtle, length, level)
myTurtle.right(120)
koch(myTurtle, length, level)
myTurtle.right(120)
myWin.exitonclick()
#4.9 写一个程序来解决这样一个问题:有2 个坛子,其中一个的容量是4 加仑,另一个的是
#3 加仑。坛子上都没有刻度线。可以用水泵将它们装满水。如何使4 加仑的坛子最后装
#有2 加仑的水?
#4.10 扩展练习9 中的程序,将坛子的容量和较大的坛子中最后的水量作为参数
def gettarget(bottle1, bottle2, a, b, target):
for _ in range(b):
bottle2.push('water')
print(f'bottle1:{bottle1.size()}')
print(f'bottle2:{bottle2.size()}')
for _ in range(a):
bottle1.push(bottle2.pop())
print(f'bottle1:{bottle1.size()}')
print(f'bottle2:{bottle2.size()}')
if bottle2.size() != target:
for _ in range(a):
bottle1.pop()
print(f'bottle1:{bottle1.size()}')
print(f'bottle2:{bottle2.size()}')
bottle1.push(bottle2.pop())
return gettarget(bottle1, bottle2, 2 * a - b, b, target)
else:
return 'complete'
def getwater():
bottle1 = Stack()
bottle2 = Stack()
gettarget(bottle1, bottle2, 3, 4, 2)
#4.11 写一个程序来解决这样一个问题:3 只羚羊和3 只狮子准备乘船过河,河边有一艘能容
#纳2 只动物的小船。但是,如果两侧河岸上的狮子数量大于羚羊数量,羚羊就会被吃掉。
#找到运送办法,使得所有动物都能安全渡河。
class passriver():
def __init__(self, a, b):
self.isfinish = False
self.change_state = [(1, 0), (0, 1), (1, 1), (2, 0), (0, 2)]
self.prst = Stack()
self.atarget = a
self.btarget = b
def riverpass(self, statea, stateb):
print(statea, stateb)
if statea[0] < statea[1] or stateb[0] < stateb[1] or statea[0] < 0 or statea[1] < 0 :
self.prst.pop()
return
if statea[0] == statea[1] == 0 and stateb[0] == self.atarget and stateb[1] == self.btarget:
self.isfinish = True
return
for cs in self.change_state:
new_statea = [statea[0] - cs[0], statea[1] - cs[1]]
new_stateb = [stateb[0] + cs[0], stateb[1] + cs[1]]
self.prst.push('%d只羊,%d只虎从a岸送往b岸' % (cs[0], cs[1]))
self.riverpass(new_statea, new_stateb)
if self.isfinish:
return
self.prst.pop()
def passrivertest():
sa, sb = [8, 8], [0, 0]
ps = passriver(sa[0], sa[1])
ps.riverpass(sa, sb)
while(ps.prst.size()):
print(ps.prst.pop())
#4.13 将行数作为参数,写一个输出帕斯卡三角形的程序
def drawpasika(n, cur):
if cur == n:
return
for i in range(cur + 1):
print(int(pasikanum(cur, i)), end = ' ')
print()
drawpasika(n, cur + 1)
def pasikanum(m, n):
if n == 0:
return 1
if n == 1:
return m
return m / n * pasikanum(m - 1, n - 1)
def pasikatest():
n = input('请输入pasika三角形的行数')
drawpasika(int(n), 0)
#4.14 01背包问题 : 动态规划
def bagproblem():
weight = [2, 3, 4, 5, 9]
value = [3, 4, 8, 8, 10]
bag_limit = 21
dp = [[0] * bag_limit for _ in range(6)]
for i in range(1, 6):
for j in range(1, bag_limit):
if j < weight[i - 1]:
#拿不起来
dp[i][j] = dp[i - 1][j]
else:
#拿得起来,但拿可能要仍,max(不拿, 拿)
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i - 1]] + value[i - 1])
return dp[5][20]
#4.15 字符串编辑距离问题 : 动态规划
def stringeditdistance(a, b):
lena, lenb = len(a) + 1, len(b) + 1
#二位数组应当如此声明
dp = [[0] * lenb for _ in range(lena)]
for i in range(lena):
dp[i][0] = i
for i in range(lenb):
dp[0][i] = i
for i in range(1, lena):
for j in range(1, lenb):
if a[i - 1] == b[j - 1]:
dp[i][j] = dp[i - 1][j - 1]
else:
dp[i][j] = min(dp[i - 1][j], min(dp[i - 1][j - 1], dp[i][j - 1])) + 1
return dp[lena - 1][lenb - 1]
def stringeditdistancetest():
print(stringeditdistance('hello', 'elloa'))