【问题标题】:Python Turtle Recursive Binary TreePython Turtle 递归二叉树
【发布时间】:2017-06-14 00:39:53
【问题描述】:

我的目标是用 python 乌龟画一棵二叉树,每条线分成 2 条,每条分支分成另外两条,依此类推,从左到右,看起来像 , 除了从左到右水平。这是我到目前为止所拥有的,它可以工作,但是如果你运行它,你很快就会意识到它在很多方面都搞砸了。

def tree(d,x1,y1):
   #d is the depth

   if d==0: #base case
       return 0

   a = t.Turtle()
   b = t.Turtle()

   t.penup()

   a.goto(x1,y1)
   b.goto(x1,y1) # move to the correct position

   t.pendown()

   a.left(30)
   b.right(30)
   a.forward(50)
   b.forward(50)

   ax,ay = a.pos() #get position of new turtles
   bx,by = b.pos()

   input() # Debug ( PRESS ENTER FOR EACH LOOP)
   tree(d-1,ax,ay)  #recurse top branch
   tree(d-1,bx,by)  #recurse bottom branch

tree(3,0,0)

谁能告诉我出了什么问题以及如何解决?我知道角度需要改变,但我不知道该怎么做。

【问题讨论】:

  • “从左到右水平”是什么意思?您的意思是要生成图形但向左旋转 90 度?如果是这样,您为什么不使用图形编辑器向我们展示旋转图,以便我们看到您想要的?如果您没有这样的编辑器,您希望我们为您做吗?
  • 这里!我尽了最大的努力用油漆,它看起来很糟糕,但我认为你应该明白这个想法!here

标签: python recursion binary-tree turtle-graphics


【解决方案1】:

我的解决方案试图重现原始示例的节点之间的角度和关系。

但是,我的主要动机是 OP 的代码和当前公认的解决方案都会生成大量海龟。这是一个问题,因为海龟在全局列表中维护,而不是垃圾收集,因此不必要地创建它们会浪费空间。在深度 4 处,到目前为止显示的算法将创建 30 个海龟,这些海龟在 tree() 运行后将不再需要且无法访问。我下面的解决方案允许您传入单个海龟以用于绘制整个图形:

from math import acos
from turtle import Turtle, Screen

DOT_DIAMETER = 20
GENERATION_DISTANCE = 75

def tree(turtle, d, origin):
    # d is the depth

    turtle.penup()
    turtle.setposition(origin)
    turtle.dot(DOT_DIAMETER)

    if d == 0:  # base case
        return

    distance = (GENERATION_DISTANCE**2 + (2**d * DOT_DIAMETER / 2)**2)**0.5
    angle = acos(GENERATION_DISTANCE / distance)

    turtle.pendown()
    turtle.left(angle)
    turtle.forward(distance)
    upper = turtle.position()
    turtle.right(angle)

    turtle.penup()
    turtle.setposition(origin)
    turtle.pendown()
    turtle.right(angle)
    turtle.forward(distance)
    lower = turtle.position()
    turtle.left(angle)

    tree(turtle, d - 1, upper)  # recurse upper branch
    tree(turtle, d - 1, lower)  # recurse lower branch

screen = Screen()

yertle = Turtle()
yertle.radians()  # to accommodate acos()

tree(yertle, 3, (-150, 0))

screen.mainloop()

输出:

您可以在tree() 之后调用screen.turtles() 以查看已创建的海龟列表。

【讨论】:

  • 哇!这是一个很棒的 waaaaaay 更整洁的方法。我不明白,也许你可以解释得更好一点,是代码中间的数学距离 = (GENERATION_DISTANCE2 + (2d * DOT_DIAMETER / 2)** 2)**0.5 角度 = acos(GENERATION_DISTANCE / 距离)
  • @notcompletelyrational,这是三角形计算之一,“鉴于我知道到下一代的(固定)距离,并且我知道我的下一代会有多宽,我应该以什么角度用于到达节点?”我不精通几何,所以可能有一种更简单的方法来表达这个方程,但要点是到每一代(列)的距离是固定的,所以随着子图占据的垂直空间的增加,角度必须增加。
【解决方案2】:

据我所知:

  1. 你应该在海龟实例ab上调用penup()pendown(),而不是在模块上。这将解决goto 上的可见线。

  2. 如果您在每个深度级别上固定长度和角度,则在第二个级别上您将开始叠加节点。 n 层上两个节点之间的垂直距离应大于 n+1 层上的距离,以确保在较低层上没有重叠节点(或边)。请注意,第 n+1 层上两个节点的垂直距离为2*forward(n)*sin(angle(n))

有点像

def tree(d,x1,y1):
   #d is the depth

   if d==0: #base case
       return 0

   a = t.Turtle()
   b = t.Turtle()

   a.penup()
   b.penup()

   a.goto(x1,y1)
   b.goto(x1,y1) # move to the correct position

   a.pendown()
   b.pendown()

   a.left(45)
   b.right(45)
   a.forward(10*(2**d)) 
   b.forward(10*(2**d))

   ax,ay = a.pos() #get position of new turtles
   bx,by = b.pos()

   tree(d-1,ax,ay)  #recurse top branch
   tree(d-1,bx,by)  #recurse bottom branch

应该可以。

【讨论】:

  • 非常感谢!看起来它确实有效!另外,为什么使用10*(2**d)?这只是为了获得更小距离的一些任意方程吗?还是有其背后的原因?如果有,是什么?
  • 我理解它的重点,它如何为每个较小的深度减小前进命令的大小,但我不明白为什么要使用这个等式
  • 一般来说,在最后一层 N,你会有 2^N 个节点。假设它们等距垂直距离d(N),则父级的2^(N-1)个节点应该间隔d(N-1) = 2*d(N)(你可以尝试画图看看)。使用该公式可确保每个父级的间距是子级间距的 2 倍,同时保持角度固定。当然,这不是唯一的方法,您可以决定改变角度以保持长度不变,或者做一些更奇特的事情。
【解决方案3】:

解决方案的一个好方法是将高度界限作为参数传递给递归函数

流程:

  1. 绘制正在访问的节点(高度边界的中间)
  2. 计算新界限;当前节点的高度将成为下子树的上界,上子树的下界
  3. 在当前节点的子节点上调用方法,具有新的边界

例子(括号是边界,每个节点-O-映射到一个实际的递归调用):

[             O            ]
[      O     ][      O     ]
[  O  ][  O  ][  O  ][  O  ]

这是我的解决方案中的一段代码(在我的 GitHub 存储库中找到整个程序:BinaryTreeVisualization)。

def draw_tree(bst, node_radius, root, bound_bottom, bound_top, x_pos, x_step):

    if (root is not None):

        # Drawing current subtree root
        root_y = (bound_bottom + bound_top) // 2
        draw_node(x_pos, root_y, node_radius)

        # Drawing bottom subtree (bottom: same, top: root_y)
        draw_tree(bst, node_radius, root.left, bound_bottom, root_y, x_pos + x_step, x_step)
        # Drawing top subtree (bottom: root_y, top: same)
        draw_tree(bst, node_radius, root.right, root_y, bound_top, x_pos + x_step, x_step)

    pass

def draw_node(x, y, radius=5):
    canvas.penup()
    canvas.goto(x, y)
    canvas.pendown()
    canvas.dot(radius * 2)
    pass

这是一棵树的example image(使用 repo 程序)

【讨论】:

    猜你喜欢
    • 2020-09-15
    • 1970-01-01
    • 2021-07-03
    • 2019-04-17
    • 2016-04-19
    • 2014-03-29
    • 2010-12-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多