• 递归 python


      ↵一、简单理解

    解决问题的一种方法,它将问题不断的分成更小的子问题,直到子问题可以用普通的方法解决。通常情况下,递归会使用一个不停调用自己的函数。

    【注】:每一次递归调用都是在解决一个更小的问题,如此进行下去,直到问题本身不能在简化为止

    例子:

    1.列表元素之和

    1. # 求列表元素之和
    2. def sumList(numlist):
    3. '''
    4. 循环计算列表和
    5. :param numlist:数值列表
    6. :return: 和
    7. '''
    8. sum = 0
    9. for num in numlist:
    10. sum += num
    11. return sum
    12. def listnum(numlist):
    13. '''
    14. 递归计算列表和
    15. :param numlist: 数值列表
    16. :return: 和
    17. '''
    18. if len(numlist) == 1:
    19. return numlist[0]
    20. else:
    21. return numlist[0] + listnum(numlist[1:])
    22. if __name__ == "__main__":
    23. numlist = [1, 2, 3, 4, 5, 6]
    24. a = sumList(numlist)
    25. b = listnum(numlist)
    26. print("循环计算结果:%f,递归计算结果:%f" % (a, b))

    2.整数转换进制

    1. # 将整数转换成以2-16为进制基数的字符串
    2. def toStr(n, base):
    3. '''
    4. 将输入的整数n转换成2-16任意进制的字符串
    5. :param n: 任意正整数
    6. :param base: 2-16中进制
    7. :return: 转换好的字符串
    8. '''
    9. convertString = "0123456789ABCDEF"
    10. if n < base:
    11. return convertString[n]
    12. else:
    13. return toStr(n // base, base) + convertString[n % base]
    14. if __name__ == "__main__":
    15. n = 10
    16. base = 2
    17. print("十进制数:%d 转换成二进制数:%s" % (n, toStr(n,base)))#字符的拼接

    另外不使用字符拼接的方式

    1. from main import Stack
    2. # 将整数转换成以2-16为进制基数的字符串
    3. rStack = Stack()
    4. def toStr(n, base):
    5. '''
    6. 将输入的整数n转换成2-16任意进制的字符串,不使用字符拼接,而是通过栈帧
    7. :param n: 任意正整数
    8. :param base: 2-16中进制
    9. :return: 转换好的数值存储栈帧
    10. '''
    11. convertString = "0123456789ABCDEF"
    12. if n < base:
    13. rStack.push(convertString[n])
    14. else:
    15. rStack.push(convertString[n % base])
    16. toStr(n // base, base)
    17. return rStack
    18. if __name__ == "__main__":
    19. n = 100
    20. base = 2
    21. numStack = toStr(n, base)
    22. print("整数%d转换为%d进制为:" % (n, base), end="")
    23. while numStack.size() >= 1:
    24. print(numStack.pop(), end="")

    二、可视化

    使用python中的画图工具进行简单递归程序的绘画,从而理解递归的概念

    1.螺旋线

    1. #用turtle模块递归的绘制螺旋线
    2. from turtle import *
    3. myTurtle = Turtle()
    4. myWin = myTurtle.getscreen()
    5. def drawSpiral(myTurtle, lineLen):
    6. if lineLen > 0:
    7. myTurtle.forward(lineLen)
    8. myTurtle.right(90)
    9. drawSpiral(myTurtle, lineLen - 5)
    10. drawSpiral(myTurtle, 100)
    11. myWin.exitonclick()#用户在窗口内再次点击之后,程序清理并退出

    2.分形树

    1. #无法绘画出来的
    2. from turtle import *
    3. myTurtle = Turtle()
    4. myWin = myTurtle.getscreen()
    5. def tree(brancheLen, t):
    6. if brancheLen > 5:
    7. t.forward(brancheLen)
    8. t.right(20)
    9. tree(brancheLen-15,t)
    10. t.left(40)
    11. tree(brancheLen-10,t)
    12. t.right(20)
    13. t.backward(brancheLen)
    14. t = Turtle()
    15. myWin = t.getscreen()
    16. t.left(90)
    17. t.up()
    18. t.backward(100)
    19. t.down
    20. tree(110,t)
    21. myWin.exitonclick()

    chatGPT中给的代码

    1. #能绘画出来
    2. import turtle
    3. def draw_branch(t, length):
    4. if length > 5:
    5. t.forward(length) # 绘制主干
    6. t.right(20) # 右转一定角度
    7. draw_branch(t, length - 15) # 递归绘制右侧分支
    8. t.left(40) # 左转一定角度
    9. draw_branch(t, length - 15) # 递归绘制左侧分支
    10. t.right(20) # 右转一定角度
    11. t.backward(length) # 返回原点
    12. def main():
    13. # 设置窗口和画笔
    14. window = turtle.Screen()
    15. window.bgcolor("white")
    16. t = turtle.Turtle()
    17. t.speed(0) # 设置绘制速度为最快
    18. # 调整画笔位置和方向
    19. t.left(90)
    20. t.up()
    21. t.backward(200)
    22. t.down()
    23. # 绘制分形树
    24. draw_branch(t, 100)
    25. # 等待用户点击关闭窗口
    26. turtle.mainloop()
    27. if __name__ == "__main__":
    28. main()

    3.谢尔平斯基三角形

    chatGPT所给的代码---可运行

    1. import turtle
    2. def draw_triangle(t, order, size):
    3. if order == 0:
    4. for _ in range(3):
    5. t.forward(size)
    6. t.left(120)
    7. else:
    8. draw_triangle(t, order - 1, size / 2)
    9. t.forward(size / 2)
    10. draw_triangle(t, order - 1, size / 2)
    11. t.backward(size / 2)
    12. t.left(60)
    13. t.forward(size / 2)
    14. t.right(60)
    15. draw_triangle(t, order - 1, size / 2)
    16. t.left(60)
    17. t.backward(size / 2)
    18. t.right(60)
    19. def main():
    20. # 设置窗口和画笔
    21. window = turtle.Screen()
    22. window.bgcolor("white")
    23. t = turtle.Turtle()
    24. t.speed(0) # 设置绘制速度为最快
    25. # 调整画笔位置和方向
    26. t.up()
    27. t.goto(-200, -150)
    28. t.down()
    29. # 绘制谢尔平斯基三角形
    30. draw_triangle(t, 5, 400)
    31. # 隐藏画笔
    32. t.hideturtle()
    33. # 等待用户点击关闭窗口
    34. turtle.mainloop()
    35. if __name__ == "__main__":
    36. main()

    b站上所学

    1. # 绘制谢尔平斯基三角形
    2. #B站--python递归三部曲(基于turtle实现可视化)
    3. import turtle
    4. t = turtle.Turtle()
    5. def get_midpoint(a, b):
    6. '''
    7. 得到两点的中点坐标
    8. :param a: 坐标点(元组)
    9. :param b: 坐标点(元组)
    10. :return: 中点坐标(元组)
    11. '''
    12. ax, ay = a
    13. bx, by = b
    14. return ((ax + bx) / 2, (ay + by) / 2)
    15. def draw_triangle(a, b, c):
    16. '''
    17. 绘制以a,b,c为顶点的三角形
    18. :param a: 顶点坐标(元组)
    19. :param b: 顶点坐标(元组)
    20. :param c: 顶点坐标(元组)
    21. :return: 无返回值
    22. '''
    23. ax, ay = a
    24. bx, by = b
    25. cx, cy = c
    26. t.penup() # 提起画笔
    27. t.goto(a) # 画笔移动到a点的位置
    28. t.pendown() # 落下画笔
    29. t.goto(b) # 画出ab线段
    30. t.goto(c) # 画出bc线段
    31. t.goto(a) # 画出ca线段
    32. t.penup()
    33. def draw_sierpinski(triangle, depth):
    34. a, b, c = triangle # triangle包括三个顶点的元组
    35. draw_triangle(a, b, c)
    36. if depth == 0:
    37. return
    38. else:
    39. d = get_midpoint(a, b)
    40. e = get_midpoint(b, c)
    41. f = get_midpoint(c, a)
    42. adf = (a, d, f)
    43. dbe = (d, b, e)
    44. fec = (f, e, c)
    45. draw_sierpinski(adf, depth - 1)
    46. draw_sierpinski(dbe, depth - 1)
    47. draw_sierpinski(fec, depth - 1)
    48. if __name__ == "__main__":
    49. triangle = ((-200,-100),(0,200),(200,-100))
    50. draw_sierpinski(triangle,4)

    4.汉诺塔

    不能可视化的

    1. #B站---python递归三部曲(基于turtle实现可视化)
    2. #汉诺塔
    3. def moveDisk(diskIndex,fromPole,toPole):
    4. '''
    5. 从起始塔向目标塔移动圆环
    6. :param diskIndex:圆环
    7. :param fromPole:起始塔
    8. :param toPole:目标塔
    9. :return:无
    10. '''
    11. print_str = 'Move disk %s from %s to %s' %(diskIndex,fromPole,toPole)
    12. print(print_str)
    13. def moveTower(height,fromPole,withPole,toPole):
    14. '''
    15. 汉诺塔的递归调用函数
    16. :param height: 汉诺塔高度
    17. :param fromPole: 起始塔
    18. :param withPole: 中转塔
    19. :param toPole: 目标塔
    20. :return:
    21. '''
    22. if height == 1:
    23. moveDisk(1,fromPole,toPole)
    24. else:
    25. moveTower(height-1,fromPole,toPole,withPole)
    26. moveDisk(height,fromPole,toPole)
    27. moveTower(height-1,withPole,fromPole,toPole)
    28. if __name__ == "__main__":
    29. moveTower(3,"A","B","C")

    能可视化的

    1. #自己对着B站视频写的一半,但是无法正确跑,不过注释都是正确的意思
    2. import turtle
    3. def set_plate(i):
    4. '''
    5. 绘制第i层圆盘
    6. :return:
    7. '''
    8. size = 20 # 圆盘转弯半径基数
    9. l = size * (i + 2) # 第i层圆盘半径
    10. t = turtle.Turtle()
    11. t.hideturtle() # 隐藏画笔
    12. t.penup() # 提起画笔
    13. t.left(90) # 每次先逆时针旋转90度,新建的左转90度为设置时的图案。
    14. t.begin_poly() # 绘制记录
    15. t.forward(l) # 向前走40
    16. t.circle(size, 180) # 画一个半径为20,角度为180的弧
    17. t.forward(l * 2)
    18. t.circle(size, 180)
    19. t.forward(l)
    20. t.end_poly() # 结束记录
    21. turtle.register_shape("plate_%s" % i, p) # 取出记录的情况,给不同层的圆盘赋值不同的名称
    22. def set_tower():
    23. '''
    24. 绘制塔
    25. :return:
    26. '''
    27. # 塔的参数:宽、高、转弯半径
    28. tower_width = 100
    29. tower_height = 200
    30. tower_radius = 10
    31. t = turtle.Turtle()
    32. t.hideturtle() # 隐藏画笔
    33. t.penup() # 提起画笔
    34. t.left(90)
    35. t.begin_poly()
    36. t.forward(tower_width)
    37. t.circle(tower_radius, 180)
    38. t.forward(tower_width - tower_radius)
    39. t.right(90)
    40. t.forward(tower_height)
    41. t.circle(tower_radius, 180)
    42. t.forward(tower_height)
    43. t.right(90)
    44. t.forward(tower_width - tower_radius)
    45. t.circle(tower_radius, 180)
    46. t.forward(tower_width)
    47. t.end_poly()
    48. turtle.register_shape("tower")
    49. def draw_towers():
    50. # 塔的参数:塔之间的距离,塔的海拔高度
    51. tower_distance = 250
    52. tower_altitude = -100
    53. set_tower()
    54. tower = turtle.Turtle("tower")
    55. tower.speed(0) # 0是最快的速度
    56. tower.penup()
    57. tower.goto(-tower_distance, tower_altitude) # 移动到(-250,-100)位置
    58. tower.stamp() # 一直显示出来
    59. tower.goto(0, tower_altitude)
    60. tower.stamp()
    61. tower.goto(tower_distance, tower_altitude)
    62. if __name__ == "__main__":
    63. draw_towers()
    64. set_plate(1)
    65. plate = turtle.Turtle("plate_1")
    66. plate.forward(200)
    67. turtle.done()

    B站博主所写代码参考网址:需要魔法(可参考网络代理文章)

    1. #能可视化代码,但是turtle库的绘制方法不熟悉
    2. import turtle
    3. # ==============
    4. # 常量设置
    5. # ==============
    6. N = 7 # 汉诺塔层数限制
    7. BasePL = 12 # plate的大小基数,修改这个能够调整plate的大小
    8. TowerP = 5 # Tower的线宽
    9. TowerW = 110 # Tower的底座宽度
    10. TowerH = 200 # Tower的高度
    11. TowerSpace = 260 # Tower的之间的距离,从中心到中心
    12. HORIZON = -100 # Tower的底座高度,用于定位
    13. # 动画速度,5是比较适中的速度
    14. PMS = 5
    15. # 优化处理
    16. Isjump = True
    17. POLES = {
    18. "1": [],
    19. "2": [],
    20. "3": [],
    21. }
    22. PLATES = [] # 存储所有圆盘对象
    23. # 塔的颜色
    24. LineColor = "black"
    25. # 多个盘子的颜色
    26. FillColors = [
    27. "#d25b6a",
    28. "#d2835b",
    29. "#e5e234",
    30. "#83d05d",
    31. "#2862d2",
    32. "#35b1c0",
    33. "#5835c0"
    34. ]
    35. # 建立窗体
    36. SCR = turtle.Screen()
    37. # SCR.tracer()
    38. SCR.setup(800, 600) # 设置窗体大小
    39. # 设置圆盘形状
    40. def set_plate(pi=0):
    41. _pi = pi + 2
    42. t = turtle.Turtle()
    43. t.hideturtle()
    44. t.speed(0)
    45. t.penup()
    46. t.begin_poly()
    47. t.left(90)
    48. t.forward(BasePL * _pi)
    49. t.circle(BasePL, 180)
    50. t.forward(BasePL * 2 * _pi)
    51. t.circle(BasePL, 180)
    52. t.forward(BasePL * _pi)
    53. t.end_poly()
    54. p = t.get_poly()
    55. pname = 'plate_%s' % pi
    56. SCR.register_shape(pname, p)
    57. # 设置塔柱形状
    58. def set_tower():
    59. t = turtle.Turtle()
    60. t.hideturtle()
    61. t.speed(0)
    62. t.penup()
    63. t.begin_poly()
    64. t.left(90)
    65. t.forward(TowerW)
    66. t.circle(-TowerP, 180)
    67. t.forward(TowerW)
    68. t.forward(TowerW)
    69. t.circle(-TowerP, 180)
    70. t.forward(TowerW - TowerP / 2)
    71. t.left(90)
    72. t.forward(TowerH)
    73. t.circle(-TowerP, 180)
    74. t.forward(TowerH)
    75. t.end_poly()
    76. p = t.get_poly()
    77. SCR.register_shape('tower', p)
    78. # 绘制塔柱
    79. def draw_towers():
    80. set_tower()
    81. for tx in [-TowerSpace, 0, TowerSpace]:
    82. t3 = turtle.Turtle('tower')
    83. t3.penup()
    84. t3.goto(tx, HORIZON)
    85. # 绘制圆盘
    86. def draw_plates(pn=4):
    87. plates = []
    88. for i in range(pn):
    89. set_plate(i)
    90. _plate = 'plate_%s' % i
    91. _p = turtle.Turtle(_plate)
    92. _colorIdx = i % len(FillColors)
    93. _color = FillColors[_colorIdx]
    94. _p.color(_color, _color)
    95. _p.speed(PMS)
    96. plates.append(_p)
    97. # 反序,大的在前,小的在后
    98. global PLATES
    99. PLATES = plates[:]
    100. # 绘制移动过程
    101. def draw_move(diskIndex, fromPindex, toPindex):
    102. p = PLATES[diskIndex - 1]
    103. index_loc = {
    104. "A": 1,
    105. "B": 2,
    106. "C": 3
    107. }
    108. toP = index_loc.get(toPindex, None)
    109. fromP = index_loc.get(fromPindex, None)
    110. p.penup()
    111. mx = (toP - 2) * TowerSpace
    112. my = HORIZON + len(POLES[str(toP)]) * BasePL * 2
    113. if fromP != None:
    114. POLES[str(fromP)].remove(p)
    115. if Isjump:
    116. px, py = p.pos()
    117. p.goto(px, TowerH + py)
    118. p.goto(mx, TowerH + py)
    119. p.goto(mx, my)
    120. POLES[str(toP)].append(p)
    121. # 将所有圆盘移动到起点
    122. def movetoA(n, fromPindex):
    123. for i in range(n, 0, -1):
    124. draw_move(i, None, fromPindex)
    125. # 移动指定层圆盘diskIndex,从fromPole出发,到达toPole
    126. def moveDisk(diskIndex, fromPole, toPole):
    127. """
    128. :param diskIndex: 圆盘的索引(从上往下,第一层为1,第二层为2、、、第n层为n)
    129. :param fromPole: 出发的柱子(起点)
    130. :param toPole: 要到达的柱子(终点)
    131. :return:
    132. """
    133. draw_move(diskIndex, fromPole, toPole)
    134. # 核心函数,入口
    135. def moveTower(height, fromPole, withPole, toPole):
    136. """
    137. :param height: 汉诺塔高度——层数
    138. :param fromPole: 出发的柱子(起点)
    139. :param withPole: 进过的柱子(中转点)
    140. :param toPole: 要到达的柱子(终点)
    141. :return:
    142. """
    143. if height == 1:
    144. # 基础情形:一层的汉诺塔
    145. moveDisk(1, fromPole, toPole)
    146. return
    147. # 先将圆盘1到n - 1看作一个整体从起点塔移动到中转塔(用目标塔作为本步骤的中转)
    148. moveTower(height - 1, fromPole, toPole, withPole)
    149. # 再将圆盘n从起点塔A移动到目标塔C
    150. moveDisk(height, fromPole, toPole)
    151. # 最后将圆盘1到n - 1看作一个整体从中转塔移动到目标塔(用起点塔作为本步骤的中转)
    152. moveTower(height - 1, withPole, fromPole, toPole)
    153. if __name__ == '__main__':
    154. # 调用
    155. # 三层汉诺塔,A为出发柱子,B为中转柱子,C为目标柱子
    156. n = N
    157. SCR.tracer(0)
    158. draw_towers()
    159. draw_plates(n)
    160. movetoA(n, "A")
    161. SCR.tracer(1)
    162. # SCR.delay(3)
    163. moveTower(n, "A", "B", "C")
    164. turtle.done()

    三、动态规划

    1.硬币找零问题

    1. def recMC(coinValueList, change):
    2. '''
    3. 找零问题
    4. :param coinValueList:零钱的数值列表
    5. :param change: 需要找的零钱总数
    6. :return: 最少找零硬币数量
    7. '''
    8. minCoins = change
    9. if change in coinValueList:
    10. return 1
    11. else:
    12. for i in [c for c in coinValueList if c <= change]:
    13. numCoins = 1 + recMC(coinValueList, change - i)
    14. # 更新最少找零数量
    15. if numCoins < minCoins:
    16. minCoins = numCoins
    17. return minCoins
    18. lst = [1,5,10,25]
    19. change = 63
    20. number = recMC(lst,change)
    21. print(number)
    22. #运行代码时,会有长时间的计算过程。

  • 相关阅读:
    hive-行转列
    Python学习—基础
    2022自编译最新稳定版newifi3固件
    【c++ primer 笔记】第11章 关联容器
    2022年高处安装、维护、拆除培训试题模拟考试平台操作
    centos7 怎么让命令行显示中文(英文->中文)
    ElasticSearch - 删除已经设置的认证密码(7.x)
    华为云云耀云服务器L实例评测|轻量级应用服务器对决:基于 Geekbench 深度测评华为云云耀云服务器L实例的处理器性能
    css 鼠标滑过组件变色
    第九章 APP项目测试(此章完结)
  • 原文地址:https://blog.csdn.net/weixin_45970022/article/details/137913095