from turtle import *
class BinaryTree:
def __init__(self,rootObj):#接受的参数是它本身和根节点两个参数
self.key = rootObj
self.leftChild = None #此时左子树和右子树都为空
self.rightChild = None
#插入左子节点
def insertLeft(self,newNode):
if self.leftChild == None: #如果原本没有左子节点,此时只需要往树中添加一个节点,如果已经存在左子节点,则插入一个节点,把原来的节点降一层
self.leftChild = BinaryTree(newNode)
else:
t = BinaryTree(newNode)
t.left = self.leftChild
self.leftChild = t
def insertRight(self, newNode):
if self.rightChild == None: # 如果原本没有左子节点,此时只需要往树中添加一个节点,如果已经存在左子节点,则插入一个节点,把原来的节点降一层
self.rightChild = BinaryTree(newNode)
else:
t = BinaryTree(newNode)
t.left = self.rightChild
self.rightChild = t
def getrightChild(self):
return self.rightChild
def getleftChild(self):
return self.leftChild
def setRootVal(self,obj):
self.key = obj
def getRootVal(self):
return self.key
def getatree():
t = BinaryTree(0)
t.leftChild=BinaryTree(1)
t.rightChild=BinaryTree(2)
temp = t.getleftChild()
temp.leftChild = BinaryTree(3)
temp.rightChild = BinaryTree(4)
temp=t.getrightChild()
temp.leftChild=BinaryTree(5)
temp.rightChild=BinaryTree(6)
return t
首先是二叉树的数据结构的定义,以及定义了一个getatree方法来快速获得一个二叉树。
下面我们来考虑绘制一个二叉树,首先,绘制一个二叉树也要把里面的元素写在旁边,在这里我们选择调用Turtle中的write()方法,其定义如下:
turtle.write(s [,font=("font-name",font_size,"font_type")])
其中,为文本内容,font是字体的参数,分别为字体名称,大小和类型;font为可选项,font参数也是可选项,在这里我们需要写出的是这一节点的元素,也就是说一个根节点的内容。到后面和绘制分形树类似使用了递归,这个时候,第一个根节点的子节点就是后面的树的根节点,首先第一次访问的则是整个二叉树的根节点0.
def drawTree(mt,tree,Len,Arg):#接受两个参数,分别是树干的长度和角度
mt.write(tree.key)
下面我们先绘制左子树,绘制左子树的条件是左子树不能为空。
if tree.leftChild:
p = mt.pos()
mt.right(Arg)
mt.fd(Len)
mt.left(Arg)
drawTree(mt,tree.leftChild,Len*0.8,Arg*0.8)
mt.up()
mt.goto(p)
mt.down()
在这里采用和绘制分形树类似的思想,首先要绘制左边的树(我们看到的左边),对Turtle来讲应该想右侧转Arg度,然后再转回来转到正方向上,接着就进入了递归,如果这个左子节点还有左子节点,继续如上让他转Arg度,往前跑Len*0.8,此时如果这个节点没有左子树了,就回到相对其现在节点的一层的根节点,然后就要绘制这个根节点的右子树了,定义如下:
if tree.rightChild:
p=mt.pos()
mt.left(Arg)
mt.fd(Len)
mt.right(Arg)
drawTree(mt,tree.rightChild,Len*0.8,Arg*0.8)
mt.up()
mt.goto(p)
mt.down()
用IDLE进行测试:
t = Turtle()
m=BinaryTree.getatree()
drawTree(t,m,100,60)
结果:
在这里补充一下类似的分形树的想法:
从之前的谢尔宾斯基三角形我们可以看出,这些递归程序都会先一直完成某一个部分直到不能继续,比如谢尔宾斯基三角形最开始一直在绘制左下角的三角形,直到左下角完全绘制完成再转过来去绘制其他部分,分形树也是如此,要绘制一棵树,我们首先要确定它的枝干的长度,以及其一条树干上的小树枝之间的角度,也就是说要确定两个变量。
一开始我们先绘制出最长的树干(A)(这很简单,只需要一个fd()),然后绘制其上的小树干(B,C),不妨定义成比这个树干短五个像素,和这个树干的夹角为20度,此时我们又绘制出了一条树干,对于它上面的小树枝(1,2...),B与(1,2...)之间的关系就和A与B的关系是一样的,和谢尔宾斯基三角形一样,他们都是由无数个类似的小基本单位组成的,因此可以使用递归,一直画到最小的单位。
from turtle import *
t=Turtle()
mywin = t.getscreen()
t.speed(1)
def draw(len,t):
if len>10:
t.forward(len)
t.right(20)
draw(len-15,t)
t.left(40)
draw(len-10,t)
t.right(20)
t.backward(len)
draw(50,t)
mywin.exitonclick()
左转四十度的原因和上面右转Arg的原因类似,