Python Turtle递归二叉树

时间:2017-06-14 00:39:53

标签: python recursion binary-tree turtle-graphics

我的目标是用python乌龟绘制一个二叉树,在这个意义上每条线分成2个,每个分支分成另外两个,等从左到右,看起来像{{0除了从左到右水平。这是我迄今为止所拥有的,并且它有效,但如果你运行它,你很快就会意识到它在很多方面都搞砸了。

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)

有人可以告诉我什么是错的,也许可以解决这个问题?我可以说角度需要改变,但我不知道该怎么做。

3 个答案:

答案 0 :(得分:1)

据我所见:

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

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

  3. 这样的东西
    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
    

    应该有用。

答案 1 :(得分: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()

<强>输出:

enter image description here

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

答案 2 :(得分:0)

解决方案的一种不错的方法是将高度限制作为参数传递给递归函数

过程:

  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(使用回购程序)