python数据结构之二叉树

2022-03-11 16:42:24 浏览数 (1)

树型结构是一类重要的非线性数据结构,其中以树和二叉树最为常用,是以分支关系定义的层次结构。树结构在客观世界中广泛存在,如人类社会的族谱和各种社会组织机构;在计算机领域中也有广泛应用,如在编译程序中,可用树来表示源程序的语法结构;在数据库系统中,树型结构也是信息的重要组织形式之一;在机器学习中,决策树,随机森林,GBDT等是常见的树模型

树的相关定义

节点:树的基本部分。它可以有一个名称,我们称之为“键”。节点也可以有附加信息。我们将这个附加信息称为“有效载荷”。虽然有效载荷信息不是许多树算法的核心,但在利用树的应用中通常是关键的。

边:树的另一个基本部分。边连接两个节点以显示它们之间存在关系。每个节点(除根之外)都恰好从另一个节点的传入连接。每个节点可以具有多个输出边。

根:树的根是树中唯一没有传入边的节点。

路径:路径是由边连接节点的有序列表。

子节点:具有来自相同传入边的节点 c 的集合称为该节点的子节点。

父节点:具有和它相同传入边的所连接的节点称为父节点。

兄弟节点:树中作为同一父节点的子节点的节点被称为兄弟节点。

子树:由父节点和该父节点的所有后代组成的一组节点和边。

叶节点:叶节点是没有子节点的节点。

高度:树的高度等于树中任何节点的最大层数。

定义一:树由一组节点和一组连接节点的边组成。树具有以下属性:

树的一个节点被指定为根节点。

除了根节点之外,每个节点 n 通过一个其他节点 p 的边连接,其中 p 是 n 的父节点。

从根路径遍历到每个节点路径唯一。

如果树中的每个节点最多有两个子节点,我们说该树是一个二叉树。

如下:

代码语言:javascript复制
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
#                     _ooOoo_
#                   o8888888o
#                    88" . "88
#                 ( | -  _  - | )
#                     O = /O
#                 ____/`---'____
#                  .' \| |// `.
#                 / \|||:|||// 
#               / _|||||-:- |||||- 
#                | | \ - /// | |
#              | _| ''---/'' | _/ |
#                .-__ `-` ___/-. /
#            ___`. .' /--.-- `. . __
#         ."" '< `.____<|>_/___.' >'"".
#       | | : `- `.;`  _ /`;.`/ - ` : | |
#            `-. _ __ /__ _/ .-` / /
#      ==`-.____`-.________/___.-`____.-'==
#                     `=---='
'''
@Project :pythonalgorithms 
@File :BinaryTree.py
@Author :不胜人生一场醉
@Date :2021/7/15 23:35 
'''

from graphviz import Digraph
import uuid
from random import sample


# 二叉树类
class BinaryTree(object):
    # 初始化
    def __init__(self, root=None):
        self.data = root  # 数据
        self.leftchild = None  # 左子树
        self.rightchild = None  # 右子树
        self.dot = Digraph(comment='Binary Tree')

    # 插入左节点
    def insertleft(self, data):
        newnode = BinaryTree(data)
        if self.leftchild == None:
            self.leftchild = newnode
        else:
            newnode.leftchild = self.leftchild
            self.leftchild = newnode
        return newnode

    # 插入右节点
    def insertright(self, data):
        newnode = BinaryTree(data)
        if self.rightchild == None:
            self.rightchild = newnode
        else:
            newnode.rightchild = self.rightchild
            self.rightchild = newnode
        return newnode

    # 二叉树的高度
    def height(self):
        # 空的树高度为0, 只有root节点的树高度为1
        if self.data is None:
            return 0
        elif self.leftchild == None and self.rightchild == None:
            return 1
        elif self.leftchild == None and self.rightchild != None:
            return 1   self.rightchild.height()
        elif self.leftchild != None and self.rightchild == None:
            return 1   self.leftchild.height()
        else:
            return 1   max(self.leftchild.height(), self.rightchild.height())

    # 访问右子节点
    def getrightchild(self):
        return self.rightchild

    # 访问左子节点
    def getleftchild(self):
        return self.leftchild

    # 设置根节点的值
    def setrootvalue(self, data):
        self.data = data

    # 获取根节点的值
    def getrootvalue(self):
        return self.data

    # 前序遍历
    def preorder(self):

        if self.data != None:
            print(self.data, end=' ')
        if self.leftchild != None:
            self.leftchild.preorder()
        if self.rightchild != None:
            self.rightchild.preorder()

    # 中序遍历
    def inorder(self):

        if self.leftchild != None:
            self.leftchild.inorder()
        if self.data != None:
            print(self.data, end=' ')
        if self.rightchild != None:
            self.rightchild.inorder()

    # 后序遍历
    def postorder(self):

        if self.leftchild != None:
            self.leftchild.postorder()
        if self.rightchild != None:
            self.rightchild.postorder()
        if self.data != None:
            print(self.data, end=' ')

    # 利用Graphviz实现二叉树的可视化
    def printtree(self, save_path='./Binary_Tree.gv', label=True):

        # colors for labels of nodes
        colors = ['skyblue', 'tomato', 'orange', 'purple', 'green', 'yellow', 'pink', 'red']

        # 绘制以某个节点为根节点的二叉树
        def print_node(node, node_tag):
            # 节点颜色
            color = sample(colors, 1)[0]
            if node.leftchild is not None:
                left_tag = str(uuid.uuid1())  # 左节点的数据
                self.dot.node(left_tag, str(node.leftchild.data), style='filled', color=color)  # 左节点
                label_string = 'L' if label else ''  # 是否在连接线上写上标签,表明为左子树
                self.dot.edge(node_tag, left_tag, label=label_string)  # 左节点与其父节点的连线
                print_node(node.leftchild, left_tag)

            if node.rightchild is not None:
                right_tag = str(uuid.uuid1())
                self.dot.node(right_tag, str(node.rightchild.data), style='filled', color=color)  # 右节点
                label_string = 'R' if label else ''  # 是否在连接线上写上标签,表明为右子树
                self.dot.edge(node_tag, right_tag, label=label_string)
                print_node(node.rightchild, right_tag)

        # 如果树非空
        if self.data is not None:
            root_tag = str(uuid.uuid1())  # 根节点标签
            self.dot.node(root_tag, str(self.data), style='filled', color=sample(colors, 1)[0])  # 创建根节点
            print_node(self, root_tag)

        self.dot.render(save_path)  # 保存文件为指定文件


if __name__ == "__main__":
    r = BinaryTree('a')
    rb = r.insertleft('b')
    print(r.getleftchild().getrootvalue())
    rc = r.insertright('c')
    rbd = rb.insertleft('d')
    rbe = rb.insertright('e')
    rcf = rc.insertleft('f')

    print('先序遍历为:')
    r.preorder()
    print()

    print('中序遍历为:')
    r.inorder()
    print()

    print('后序遍历为:')
    r.postorder()
    print()

    # rcfg = rcf.insertleft('g')
    # print('先序遍历为:')
    # r.preorder()
    # print()
    rcfg = rc.insertleft('g')
    print('先序遍历为:')
    r.preorder()
    print()

    r.setrootvalue('aaa')
    print('先序遍历为:')
    r.preorder()
    print()
    print('根节点的值为')
    print(r.getrootvalue())
    print('树的高度是:')
    print(r.height())

    r.printtree()

运行结果如下:

代码语言:javascript复制
先序遍历为:
a b d e c f 
中序遍历为:
d b e a f c 
后序遍历为:
d e b f c a 
先序遍历为:
a b d e c g f 
先序遍历为:
aaa b d e c g f 
根节点的值为
aaa
树的高度是:
4

0 人点赞