1. 树的概念
树是一种非线性结构
1.1 树的相关概念
1.1.1 节点的度
一个节点含有的子节点的个数,称为该节点的度,例如A节点的度为3
1.1.2 树的度
一棵树中,最大的节点的度称为树的度。例如下图中树的度为3
1.1.3 叶节点
度数为零的节点。例如:C E F
1.1.4 节点的层次
从根开始算起,根为第一层,根的子节点为第2层,以此类推。
1.1.5 树的高度/深度
树中节点的最大层次,即最多的层次有几层。例如下图中,树的高度为3
1.2 树的特点
- 每个节点有零个或多个子节点
- 没有父节点的节点称为根节点
- 每一个非根节点,有且只有一个父节点
- 除了根节点外,每个子节点可以分为多个不想交的子树。
2. 二叉树
每个节点最多含有两个子树的树称为二叉树。
二叉树的种类有很多,例如:完全二叉树、非完全二叉树、满二叉树等。
2.1 完全二叉树
对于一棵二叉树,假设其深度为d(d>1),除了第d层外,其它各层的节点数均已达到最大值,且第d层所有节点从左向右依次的紧密排列。
2.2 非完全二叉树
2.3 满二叉树
所有叶节点都在最底层的完全二叉树
2.4 平衡二叉树(AVL树)
当且仅当任何节点的两棵子树的高度差不大于1的二叉树
2.5 排序二叉树(BST)
排序二叉树有以下要求:
- 若左子树不空,则左子树上所有节点的值均小于它的根节点的值
- 若右子树不空,则右子树上所有节点的值均大于它的根节点的值
- 左右子树也分别为二叉排序树
空树也是排序二叉树。
3. 二叉树的实现
3.1 二叉树的性质
- 在第 i 层上,至多有2^(i-1)个节点(i>0)
- 深度为k的二叉树,至多有2^k - 1 个节点
- 对于任意一棵二叉树,如果其叶节点数为a,而度数为2的节点总数为b,则a = b +1
- 最多有n个节点的完全二叉树的深度必为log2(n+1) 即 log以2为底,n+1 的对数
- 对完全二叉树,从上至下,从左至右编号,编号为i的结点,左孩子必为2i,右孩子必为2i+1,父节点必为i/2(i=1时为根节点,除外)
3.2 二叉树的添加节点的实现
实现思路:
- 判断是否有根节点,如果没有,则添加根节点
- 如果有根节点,则创建一个临时的队列,将根节点入队列,然后将根节点出队列
- 判断出队列的节点是否包含左节点,如果包含则将左节点入队列,如果不包含则直接指向待添加的节点
- 判断出队列的节点是否包含右节点,如果包含则将对应的节点入队列,不包含则直接指向待添加的节点
例如:添加节点7
首先1进队列,然后1出队列,1有左节点2,2进队列。1有右节点3,3进队列。
2出队列,2有左节点4,4进队列。2有左节点5,5进队列
3出队列,3有左节点6,6进队列,3没有右节点,则3的右节点指向节点7
添加完成
代码实现
class MyBinaryTree(object):
def __init__(self, tree_node=None):
self.root = tree_node
def add_node(self, tree_node):
# 根节点为空
if self.root is None:
self.root = tree_node
return
# 根节点不为空
# 新增一个临时队列
temp_queue = MyQueue()
# 将头结点添加到队列
temp_queue.append_end(self.root)
while temp_queue.size() > 0:
# 出队列
temp_node = temp_queue.del_head()
if temp_node.lNode is not None:
temp_queue.append_end(temp_node.lNode)
else:
temp_node.lNode = tree_node
return
if temp_node.rNode is not None:
temp_queue.append_end(temp_node.rNode)
else:
temp_node.rNode = tree_node
return
3.2 二叉树的广度优先遍历
从根节点开始,按照层级顺序逐层遍历所有的节点。
如下图:广度优先遍历结果为:0 1 2 3 4 5 6 7 8 9
代码实现
def breath_first_search(self):
"""
广度优先遍历
:return:None
"""
# 先判断是否有根节点
if self.root is None:
return None
# 存在根节点
temp_queue = MyQueue()
temp_queue.append_end(self.root)
while temp_queue.size() > 0:
temp_node = temp_queue.del_head()
print(f"{temp_node.value}", end=" ")
if temp_node.lNode is not None:
temp_queue.append_end(temp_node.lNode)
if temp_node.rNode is not None:
temp_queue.append_end(temp_node.rNode)
3.3 二叉树的深度优先遍历
3.1 先序遍历
即按照根节点、左节点、右节点的顺序来遍历。
例如: 0 1 3 7 8 4 9 2 5 6
3.2 中序遍历
即按照左节点、根节点、右节点的顺序来遍历。
例如:7 3 8 1 9 4 0 5 2 6
3.3 后序遍历
即按照左节点、右节点、根节点的顺序来遍历。
例如:7 8 3 9 4 1 5 6 2 0
知道中序遍历和先序遍历(或者是后序遍历) 就可以推出二叉树结构。
3.4 代码实现
def depth_first_search(self, tree_node, front=False, middle=False, back=False):
if tree_node is not None:
if front and not middle and not back:
# 先序遍历,根左右
print(tree_node.value, end=" ")
self.depth_first_search(tree_node.lNode, front=True)
self.depth_first_search(tree_node.rNode, front=True)
elif middle and not front and not back:
# 中序遍历,左根右
self.depth_first_search(tree_node.lNode, middle=True)
print(tree_node.value, end=" ")
self.depth_first_search(tree_node.rNode, middle=True)
elif back and not middle and not front:
# 后序遍历,左右根
self.depth_first_search(tree_node.lNode, back=True)
self.depth_first_search(tree_node.rNode, back=True)
print(tree_node.value, end=" ")