目录
前言
一、树
逻辑结构:层次结构
物理结构:顺序存储、链式存储
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)
- 二叉树的第
k
层上的结点最多个
个 - 深度为
k
的二叉树最多有
个结点 - 在任意一颗二叉树中,树叶的数目比度数为
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
左----->根----->右
四、链式存储
链式存储此二叉树,从根结点开始,将各个结点以及其左右子的地址使用链表进行存储。
完全二叉树中结点按照层次并从左到右依次编号(1
2
3
...
),若结点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)
总结
二叉树作为典型的非线性数据结构,通过父子节点关系体现层次逻辑,其顺序存储要求完全二叉树形态并通过数组下标映射节点位置,而链式存储则通过左右指针灵活表达任意树形结构;遍历算法中前序、中序、后序分别对应不同处理顺序,递归实现简洁体现分治思想,层次遍历则需借助队列完成广度优先搜索;示例代码通过编号规则递归生成完全二叉树,直观展现节点创建过程,输出结果验证了三种遍历方式的特性差异。掌握这些核心知识点,可有效应用于文件系统管理、表达式解析、优先队列实现等实际场景,为算法学习奠定坚实基础。