Python数据结构与算法分析(第二版)答案-第四章(仅供参考)

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'))

你可能感兴趣的:(python,数据结构)