一、树形结构(层次结构)
1.1 基本概念
树形结构:数据元素之间存在一对多的关系
树:树是由根结点和若干个子结点组成的树形结构
结点:树的基本单位
根结点:没有父结点的节点称为根结点
父结点:当前结点的直接上级节点称为该节点的父结点
孩子结点:当前结点的直接下级节点称为该节点的孩子节点
兄弟节点:拥有相同父结点的结点互为兄弟节点
堂兄弟结点:其父结点在同一层次的结点互为堂兄弟结点
祖先结点:当前结点的直接或间接上级节点
子孙节点:当前结点的直接或间接下级节点
叶子节点:度为0的节点,或者说是没有孩子节点的节点
节点的度:就是该节点的子节点的个数
树的度:当前树中的节点的度的最大值就是树的度
节点的层次:从根结点出发,到该节点处所经历的层次称为该节点的层次
树的层次(深度):节点层次的最大值就是树的层次
森林:由m(m>=0)个不相交的树构成的树形结构叫做森林
1.2 二叉树
每个节点最多拥有两个节点的树,并且严格区分左右子树的树形结构。
1.3 二叉树的相关概念
1】左子树:以当前节点的左孩子为根节点的子树称为该节点的左子树
2】右子树:以当前节点的右孩子为根节点的子树称为该节点的右子树
3】左斜树:该树上的每个节点都只有左孩子节点,没有右孩子节点的树
4】右斜树:该树上的每个节点都只有右孩子节点,没有左孩子节点的树
5】满二叉树:在不增加层次的基础上,不能再向树上增加节点
6】完全二叉树:在满二叉树的基础上,从左往右依次增加节点的二叉树叫完全二叉树
1.5 二叉树的性质
1】在一个二叉树的第i层上,最多拥有2^(i-1)个节点
2】前k层最多拥有2^k - 1个节点
3】在任意一个二叉树上,叶子节点的个数总比度为2的节点数目多一个
总节点数 = 总度树+1 n0 表示度为0 的节点 n1表示度为1的节点 n2表示度为2的节点
总节点数:n0+n1+n2
总度数:n1*1 + n2*2
n0+n1+n2 = n1*1 + n2*2 +1 n0 = n2 +1
1.6 二叉树的顺序存储
对于树的顺序存储而言,如果是满二叉树或者是完全二叉树的话,使用顺序存储没有任何问题,但是,如果是普通二叉树,那就会造成空间浪费,所以,一般对二叉树的存储,通常使用链式存储。
1.7 二叉树的链式存储
1.7.1 节点和树类的类型封装
#封装树的节点的类
class Node:
#显性定义构造函数
def __init__(self,data,lchild = None, rchild = None):
self.data = data #树节点的数据域
self.lchild = lchild #左孩子的位置
self.rchild = rchild #右孩子的位置
#封装树的类型
class Tree:
#构造函数
def __init__(self,root = None):
self.root = root #树的根
self.index = 0 #用于遍历一串数据的索引
1.7.2 创建二叉树
#二叉树的创建
def tree_create(self,data_str):
if self.index >= len(data_str):
return None
#获取一个节点的数据
data = data_str[self.index]
self.index+=1
if data == '#':
return None
#创建节点
node = Node(data)
node.lchild = self.tree_create(data_str)#递归创建左子树
node.rchild = self.tree_create(data_str)#递归创建右子树
return node
1.7.3 先序遍历
功能:每次遍历到节点时,先访问数据域,然后访问左子树,最后访问右子树。 ----->根 左 右
#先序遍历
def pri_show(self,node):
if node is not None:
#根
print(node.data, end=' ')
#左
self.pri_show(node.lchild)
#右
self.pri_show(node.rchild)
1.7.4 中序遍历
功能:每次遍历到节点时,先访问左子树,然后访问数据域,最后访问右子树。 ----->左 根 右
# 中序遍历
def mid_show(self, node):
if node is not None:
# 左
self.mid_show(node.lchild)
# 根
print(node.data, end=' ')
# 右
self.mid_show(node.rchild)
1.7.5 后序遍历
功能:每次遍历到节点时,先访问数据域,然后访问问右子树,最后访问数据域。 ----->左 右 根
# 后序遍历
def last_show(self, node):
if node is not None:
# 左
self.last_show(node.lchild)
# 右
self.last_show(node.rchild)
# 根
print(node.data, end=' ')
代码:
#封装树的节点的类
class Node:
#显性定义构造函数
def __init__(self,data,lchild = None, rchild = None):
self.data = data #树节点的数据域
self.lchild = lchild #左孩子的位置
self.rchild = rchild #右孩子的位置
#封装树的类型
class Tree:
#构造函数
def __init__(self,root = None):
self.root = root #树的根
self.index = 0 #用于遍历一串数据的索引
#二叉树的创建
def tree_create(self,data_str):
if self.index >= len(data_str):
return None
#获取一个节点的数据
data = data_str[self.index]
self.index+=1
if data == '#':
return None
#创建节点
node = Node(data)
node.lchild = self.tree_create(data_str)#递归创建左子树
node.rchild = self.tree_create(data_str)#递归创建右子树
return node
#先序遍历
def pri_show(self,node):
if node is not None:
#根
print(node.data, end=' ')
#左
self.pri_show(node.lchild)
#右
self.pri_show(node.rchild)
# 中序遍历
def mid_show(self, node):
if node is not None:
# 左
self.mid_show(node.lchild)
# 根
print(node.data, end=' ')
# 右
self.mid_show(node.rchild)
# 后序遍历
def last_show(self, node):
if node is not None:
# 左
self.last_show(node.lchild)
# 右
self.last_show(node.rchild)
# 根
print(node.data, end=' ')
#测试
if __name__ == "__main__":
#输入一组数据
data_str = input("输入二叉树的序列:")
#创建二叉树
tree = Tree()
tree.root = tree.tree_create(data_str)
#遍历
print("先序遍历结果:")
tree.pri_show(tree.root)
print()
print("中序遍历结果:")
tree.mid_show(tree.root)
print()
1.8 根据已知序列反推二叉树
1】由先序序列和中序序列反推二叉树
已知树画遍历也很简单,记住遍历的顺序如左右根,每一个结点画完左右根之后依次按顺序细分,直到分完了按层次书写
2】由后序序列和中序序列反推二叉树
3】不能通过先序和后序返推二叉树
缺乏结构信息:
- 先序遍历的顺序是:根节点 -> 左子树 -> 右子树。
- 后序遍历的顺序是:左子树 -> 右子树 -> 根节点。
这两种遍历方式都只提供了节点访问的顺序,而没有提供关于节点之间连接关系的明确信息。特别是,它们都没有明确说明哪些节点是哪些节点的父节点、左子节点或右子节点