深入解析二叉树:从存储结构到遍历算法的Python实现全解

目录


前言

书接上文链式栈、顺序队列与链式队列的实现原理与Python代码全解析-CSDN博客文章浏览阅读702次,点赞35次,收藏7次。本文深度剖析链式栈、顺序队列与链式队列的底层逻辑与Python实现,涵盖无头链表实现链式栈的入栈/出栈优化、循环数组解决顺序队列的“假溢出”问题、链式队列的头尾指针分离操作等关键技术,通过代码详解与性能对比,揭示不同数据结构在动态性、空间效率与操作复杂度上的核心差异,为开发者灵活选型提供理论依据与实践参考。 https://blog.csdn.net/qq_58364361/article/details/146308626?fromshare=blogdetail&sharetype=blogdetail&sharerId=146308626&sharerefer=PC&sharesource=qq_58364361&sharefrom=from_link


 一、树


逻辑结构:层次结构
物理结构:顺序存储、链式存储


1.1 概念

二叉树(binary tree)是一种非线性数据结构,代表“祖先”与“后代”之间的派生关系,体现了“一分为二”的分治逻辑。与链表类似,二叉树的基本单元是节点,每个节点包含值、左子节点引用和右子节点引用。

个节点都有两个引用(指针),分别指向左子节点(left-child node)和右子节点(right-child node),该节点被称为这两个子节点的父节点(parent node)。当给定一个二叉树的节点时,我们将该节点的左子节点及其以下节点形成的树称为该节点的左子树(left subtree),同理可得右子树(right subtree)。


1.2 性质

关于树的一些基本念

(1)度数:一个节点的子树的个数(一个节点的子树的个数称为该节点的度数)

(2)树度数:树中节点的最大度数,二叉树的树度数最大为2

(3)叶节点或终端节点: 度数为零的节点

(4)分支节点:度数不为零的节点(B一层)

(5)内部节点:除根节点以外的分支节点 (B,C,D)

(6)节点层次: 根节点的层次为1,根节点子树的根为第2层,以此类推

(7)树的深度或高度: 树中所有节点层次的最大值 (4)

  1. 二叉树的第k层上的结点最多个2^{k-1}
  2. 深度为k的二叉树最多有2^{k-1}个结点
  3. 在任意一颗二叉树中,树叶的数目比度数为2的结点数目多1

【练习】一棵二叉树有8个度为2的节点,5个度为1的节点,那么度为0的节点个数为 ( )

答案:9

 满二叉树和完全二叉树

满二叉树:深度为k(k>=1)时,第k层结点个数为2k-1

完全二叉树:只有最下面两层有度数小于2的节点,且最下面一层的结点集中在最左边的若干位置上。


二、顺序存储

二叉树的顺序存储,指的是使用顺序表(数组、列表)存储二叉树。需要注意,顺序存储只适用于完全二叉树。换句话说,只有完全二叉树才可以用顺序表存储。因此,如果我们想要顺序存储普通二叉树,就需要将其提前转换成完全二叉树。

普通二叉树转完全二叉树的方法很简单,只需给二叉树额外添加一些结点,将其"拼凑"成一个完全二叉树即可。

如图所示:

左侧是普通二叉树,右侧是转化后的完全(满)二叉树。

全(满)二叉树的顺序存储,仅需要从根结点开始,按照层次依次将树中结点存储到数组即可。

存储图 2 所示的完全二叉树:

储由普通二叉树转化来的完全二叉树也是如此。

图 1 中普通二叉树在顺组中的存储状态如图:


三、树的遍历方式

前序遍历(先序):根左右

中序遍历:左根右

后序遍历:左右根

层次遍历

先序:根----->左----->右

ABDHIEJCFKG

中序:左----->根----->右

HDIBEJAFKCG

后序:左----->右----->根

HIDJEBKFGCA

练习:

已知遍历结果如下,试画出对应的二叉树,写出后序:

先序:A B C E H F I J D G K 根----->左----->右

中序:A H E C I F J B D K G 左----->根----->右


四、链式存储

链式存储此二叉树,从根结点开始,将各个结点以及其左右子的地址使用链表进行存储。

完全二叉树中结点按照层次并从左到右依次编号(123...),若结点i有左子,则其左子的结点编号为2*i,右子编号为2*i+1

设完全二叉树的结点数为n,某结点的编号为i

i>1时(不是根结点时),有父节点,其编号为i/2

2*i <= n时,有左子,其编号为2*i,否则没有左子,没左子一定没右子,其本身为叶节点。

2*i+1 <= n时,有右子,其编号为2*i+1,否则就没有右子。


4.1 接口 

class TreeNode:
    def __init__(self, data=None, left=None, right=None):
        self.data = data
        self.left = left
        self.right = right
        
def create_bitree(n, i):
    pass
    
def pre_order(r):
    pass
    
def in_order(r):
    pass
    
def post_order(r):
   pass

4.2 创建二叉树

def create_bitree(n, i):  # n = 3
    root = TreeNode(i)
    if 2 * i <= n:
        root.left = create_bitree(n, 2 * i)
    else:
        root.left = None

    if 2 * i + 1 <= n:
        root.right = create_bitree(n, 2 * i + 1)
    else:
        root.right = None

    return root

4.3 先序遍历

def pre_order(r):
    if r is None:
        return
    print(r.data, end=' ')
    pre_order(r.left)
    pre_order(r.right)

4.3 中序遍历

def in_order(r):
    if r is None:
        return
    in_order(r.left)
    print(r.data, end=' ')
    in_order(r.right)

4.4 后序遍历

def post_order(r):
    if r is None:
        return
    post_order(r.left)
    post_order(r.right)
    print(r.data, end=' ')

4.5 整体代码

class TreeNode:
    def __init__(self, data=None, left=None, right=None):
        self.data = data
        self.left = left
        self.right = right


def create_bitree(n, i):  # n = 3
    root = TreeNode(i)
    if 2 * i <= n:
        root.left = create_bitree(n, 2 * i)
    else:
        root.left = None

    if 2 * i + 1 <= n:
        root.right = create_bitree(n, 2 * i + 1)
    else:
        root.right = None

    return root


def pre_order(r):
    if r is None:
        return
    # 根
    print(r.data, end='')
    # 左
    pre_order(r.left)
    # 右
    pre_order(r.right)

    return


def in_order(r):
    if r is None:
        return
    # 左
    in_order(r.left)
    # 根
    print(r.data, end='')
    # 右
    in_order(r.right)


def post_order(r):
    if r is None:
        return
    # 左
    post_order(r.left)
    # 右
    post_order(r.right)
    # 根
    print(r.data, end='')


n = 3  # 树的节点(编号从1号开始)

root = create_bitree(n, 1)
print("前序遍历:")
pre_order(root)
print("\n中序遍历:")
in_order(root)
print("\n后序遍历:")
post_order(root)


总结 

        二叉树作为典型的非线性数据结构,通过父子节点关系体现层次逻辑,其顺序存储要求完全二叉树形态并通过数组下标映射节点位置,而链式存储则通过左右指针灵活表达任意树形结构;遍历算法中前序、中序、后序分别对应不同处理顺序,递归实现简洁体现分治思想,层次遍历则需借助队列完成广度优先搜索;示例代码通过编号规则递归生成完全二叉树,直观展现节点创建过程,输出结果验证了三种遍历方式的特性差异。掌握这些核心知识点,可有效应用于文件系统管理、表达式解析、优先队列实现等实际场景,为算法学习奠定坚实基础。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夜松云

请投喂云云喵,谢谢喵!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值