蟒海龟递归二叉树

问题描述:

我的目标是用蟒龟绘制一棵二叉树,意思是每条线分成2条,每条分支到另外两条等,从左到右,看起来像this,除了从左到右水平。这是我到目前为止所拥有的,并且它可以工作,但是如果你运行它,你很快就会意识到它在很多方面都是混乱的。蟒海龟递归二叉树

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) 

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

+0

“水平从左到右”是什么意思?你的意思是你想产生你的图形,但向左旋转90度?如果是这样,为什么不使用图形编辑器并向我们展示旋转的图表,以便我们看到你想要的?如果你没有这样的编辑器,你想让我们为你做这个吗? –

+0

在这里!我尽力用油漆,它看起来很糟糕,但我认为你应该明白![这里](http://imgur.com/Pwg3Dkl) – notcompletelyrational

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

但是,我的主要动机是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() 

OUTPUT:

enter image description here

可以tree()后打电话screen.turtles()看到海龟的列表已经创建。

+0

哇!这是一个令人敬畏的waaaaaay整洁的方式来做到这一点。什么我不明白,也许你可以解释一点点更好,是代码中间的数学运算距离=(GENERATION_DISTANCE ** 2 +(2 ** d * DOT_DIAMETER/ 2)** 2 )** 0.5 angle = acos(GENERATION_DISTANCE/distance) – notcompletelyrational

+0

@不完全合理,这是三角计算之一,“因为我知道与下一代的(固定)距离,并且我知道我的下一代会有多宽是,我应该用什么角度来达到节点?“我并不擅长几何,所以可能有更简单的方法来表达这个方程,但其要点是与每一代(列)的距离是固定的,所以角度必须随着子图占据的垂直空间的增加而增加。 – cdlane

至于我可以看到:

  1. 你应该叫penup()pendown()在龟实例ab,而不是模块。这将解决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 

应该工作。

+0

非常感谢!它看起来像它的工作!另外,为什么使用'10 *(2 ** d)'?那只是一些任意的方程式,只是为了获得更小的距离?或者背后有推理吗?如果是这样,什么? – notcompletelyrational

+0

我明白了它的意义,它是如何减小每个较小深度的正向命令的大小的,但我不明白为什么这个方程恰好被使用了 – notcompletelyrational

+0

一般来说,在最后一级N上,你将有2^N节点。假设它们以垂直距离'd(N)'等距间隔,则父层的2 ^(N-1)个节点应该被间隔d(N-1)= 2 * d(N)你可以尝试绘制看到它)。使用该公式可以确保每个父级别的间距是子级间距的2倍,同时保持角度不变。当然,这不是唯一的方法,你可以决定改变角度以固定长度,或做一些更具异国情调的东西。 – user1620443