算法基础知识学习——二叉树的绘制

基于二叉堆的二叉树绘制方法

算法基础知识学习——二叉树的绘制_第1张图片
介于目前网上二叉树绘制的python代码太过复杂难懂,并且有些画的太过于丑,因此写下该文章。
注:本文所述方法中的二叉树以链表的形式存储。

1 绘图前准备。

首先你的二叉树要以链表的形式存储,你的节点类中方法的命名要如下所示:

class BinaryTree:
    def __init__(self,value):
        self.value=value
        self.left=None
        self.right=None
        self.indexInHeap=None
    def getIndexHeap(self):
        return self.indexInHeap
    def setIndexHeap(self,value):
        self.indexInHeap=value
    def insertLeft(self,newNode):
        if self.left==None:
            self.left=BinaryTree(newNode)
        else:
            t=BinaryTree(newNode)
            t.left=self.left
            self.left=t
    def insertRight(self,newNode):
        if self.right==None:
            self.right=BinaryTree(newNode)
        else:
            t=BinaryTree(newNode)
            t.right=self.right
            self.right=t
    def getValue(self):
        return self.value
    def setValue(self,value):
        self.value=value
    def getRightChild(self):

        return self.right
    def getLeftChild(self):
        return self.left

2、绘图的基本思想

首先通过二叉树的高度,得出最底层满二叉树的叶子节点树,随后将该树满二叉树的叶节点求出,然后层层向上递推,求出所有节点的坐标,然后存为二叉堆数组。同时将你的二叉树存为二叉堆数组,二者一一对应,通过mathplo的annotate进行绘制。
注:有人回复的时候我再介绍详细的思想;
所有涉及的函数以及简单示例如下:

import matplotlib.pyplot as plt
from  treeClass import myOwnTree
def getNumberOfLeafs(tree):
    leafNumber = 0##对应none节点
    if tree:
        if  not tree.getRightChild() and not tree.getLeftChild():
            leafNumber+=1
        else:
            leafNumber+=getNumberOfLeafs(tree.getLeftChild())
            leafNumber += getNumberOfLeafs(tree.getRightChild())
    return leafNumber
def getDeepOfTree(tree):
    maxDeep=0#不符合情况的那个是0
    if tree:
        maxLeft=getDeepOfTree(tree.getLeftChild())
        maxRight=getDeepOfTree(tree.getRightChild())
        if maxLeft>maxRight:
            maxDeep=maxLeft
            return 1+maxLeft
        else:
            maxDeep=maxRight
            return 1+maxRight
    return maxDeep

def printTreePre(tree):
    if tree:
        print(tree.getValue())
        printTreePre(tree.getLeftChild())
        printTreePre(tree.getRightChild())
    # tree(treeLen-4)
def getDuiIndex(tree):
    if tree:
        if tree.getLeftChild():
            tree.getLeftChild().setIndexHeap(2*tree.getIndexHeap())
        if tree.getRightChild():
            tree.getRightChild().setIndexHeap(2 * tree.getIndexHeap()+1)
        getDuiIndex(tree.getLeftChild())
        getDuiIndex(tree.getRightChild())
def getDuiHelp(list,tree):
    if tree:
        list[tree.getIndexHeap()]=tree.getValue()
        getDuiHelp(list,tree.getLeftChild())
        getDuiHelp(list,tree.getRightChild())
    return list
def getDuiList(tree):
    getDuiIndex(tree)#给每个节点添加堆序号
    h=getDeepOfTree(tree)
    res=[None for i in range(2**h-1)]
    res.insert(0,0)

    return getDuiHelp(res,tree)
def drawBinaryTree(r,nodeType=dict(boxstyle="round", fc=(1.0, 0.7, 0.7), ec="none")):
    # 接下来用我的方式画这个图
    fig = plt.figure(1, facecolor="white")
    fig.clf()
    ax1 = plt.subplot(111, frameon=False)
    h = getDeepOfTree(r)
    if h==1:#如果只有一层
        ax1.annotate(r.getValue(), va="center", ha="center", xy=(0.5,0.5), bbox=nodeType)  ##画出这个点
        return None
    w = getNumberOfLeafs(r)
    detH = 1 / (h - 1)
    yAxis = []
    startY = 0
    while startY <= 1:
        yAxis.append(startY)
        startY += detH
    allLeafs = 2 ** (h - 1)
    detX = 1 / (allLeafs - 1)
    leafPos = []
    startX = 0
    while startX <= 1:
        leafPos.append(startX)
        startX += detX
    allXList = []
    while len(leafPos) >= 1:
        allXList.append(leafPos)
        tempList = []
        i = 0
        while i < len(leafPos) - 1:
            tempList.append((leafPos[i] + leafPos[i + 1]) / 2)
            i += 2
        leafPos = tempList
    allXList = allXList[::-1]
    finPos = []
    for xList, y in zip(allXList, yAxis[::-1]):
        for item in xList:
            finPos.append([item, y])
    finPos.insert(0, 0)  # 为了使下标满足左右子树之间的关系,这里在开始的位置添加占位符
    ##接下来将二叉树存为二叉堆的形式
    r.setIndexHeap(1)
    duiListForR = getDuiList(r)
    ##开始画
    for i in range(1, len(duiListForR)):
        if duiListForR[i]:
            ##然后画出这个点指出去的箭头
            if 2*i<len(duiListForR) and duiListForR[2*i]:##往左指
                ax1.annotate("", xy=(finPos[i][0], finPos[i][1]),xytext=(finPos[2*i][0],finPos[2*i][1]),va="center", ha="center",bbox=nodeType,arrowprops=dict(arrowstyle="<-"))##画出这个点
            if 2*i+1<len(duiListForR) and duiListForR[2*i+1]:#往右指
                ax1.annotate("", xy=(finPos[i][0], finPos[i][1]),xytext=(finPos[2*i+1][0],finPos[2*i+1][1]),va="center", ha="center",bbox=nodeType,arrowprops=dict(arrowstyle="<-"))##画出这个点
    for i in range(1, len(duiListForR)):
        if duiListForR[i]:
            ax1.annotate(duiListForR[i],va="center", ha="center",xy= (finPos[i][0], finPos[i][1]),bbox=nodeType)##画出这个点


if __name__ == '__main__':
    r = myOwnTree.BinaryTree("a")
    r.insertLeft("b")
    r.insertRight("c")
    r.getRightChild().insertLeft("d")
    r.getRightChild().getLeftChild().insertRight("g")
    r.getLeftChild().insertRight("f")
    r.getLeftChild().insertLeft("h")
    r.getLeftChild().getLeftChild().insertLeft("i")
    r.getLeftChild().getLeftChild().insertRight("k")
    r.getLeftChild().getLeftChild().getLeftChild().insertRight("l")
    r.getLeftChild().getLeftChild().getLeftChild().insertLeft("m")
    # ##生成一个图片,图片上进行注释
    # toothType=dict(boxstyle="sawtooth", fc="0.8")#波浪形
    leafNod=dict(boxstyle="round", fc=(1.0, 0.7, 0.7), ec="none")#圆形
    drawBinaryTree(r,leafNod)

绘制的效果如下图所示:
算法基础知识学习——二叉树的绘制_第2张图片

3、如果你觉得上面写的过于麻烦

如果你对绘制和二叉树的操作过程不求甚解,只求应用的话,我的代码已经上到了git上。
github上的代码
下载下来之后将里面的两个文件夹拷到你的项目里,然后就可以直接引用了:

#画图函数
import drawPicture.viewBinaryTree as binaryView
#导入二叉树的构建类
from treeClass.myOwnTree import BinaryTree
##随意构建树
r = BinaryTree("a")
r.insertLeft("b")
r.insertRight("c")
r.getRightChild().insertLeft("d")
r.getRightChild().getLeftChild().insertRight("g")
r.getLeftChild().insertRight("f")
##画出来
leafNod=dict(boxstyle="round", fc=(1.0, 0.7, 0.7), ec="none")
binaryView.drawBinaryTree(r,leafNod)

你可能感兴趣的:(算法巩固)