树的概念
树
(
英语:tree)就是一种非线性结构
它是用来模拟具有树状结构性质的数据集合. 它是由n(n>=1)个有限节点组成一个具有层次
关系的集合。把它叫做 “树”是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的.
树的特点
①每个节点有零个或多个子节点
②没有父节点的节点称为根节点
③每一个非根节点有且只有一个父节点
④除了根节点外,每个子节点可以分为多个不相交的子树
树的术语
节点的度:一个节点含有的子节点的个数称为该节点的度
树的度:一棵树中,最大的节点的度称为树的度
叶节点或终端节点:度为零的节点
父亲节点或父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点
孩子节点或子节点:一个节点含有的子树的根节点称为该节点的子节点
兄弟节点:具有相同父节点的节点互称为兄弟节点
节点的层次:从根开始定义起,根为第1层,根的子节点为第2层,以此类推
树的高度或深度:树中节点的最大层次
堂兄弟节点:父节点在同一层的节点互为堂兄弟
节点的祖先:从根到该节点所经分支上的所有节点
子孙:以某节点为根的子树中任一节点都称为该节点的子孙
森林:由m(m>=0)棵互不相交的树的集合称为森林
树的种类
无序树:树中任意节点的子节点之间没有顺序关系,这种树称为无序树,也称为自由树
有序树:树中任意节点的子节点之间有顺序关系,这种树称为有序树
二叉树:每个节点最多含有两个子树的树称为二叉树
二叉树的种类
完全二叉树:对于一颗二叉树,假设其深度为d(d>1)。除了第d层外,其它各层的节点数目均
已达最大值,且 第d层所有节点从左向右连续地紧密排列,这样的二叉树被称为完全二叉树
满二叉树的定义是所有叶节点都在最底层的完全二叉树
平衡二叉树(AVL树):当且仅当任何节点的两棵子树的高度差不大于1的二叉树
排序二叉树:
1.若左子树不空,则左子树上所有节点的值均小于它的根节点的值
2.若右子树不空,则右子树上所有节点的值均大于它的根节点的值
3.左、右子树也分别为二叉排序树
二叉树概念
二叉树是每个节点最多有两个子树的树结构,通常子树被称作“左子树”和“右子树”
二叉树的性质
性质1: 在二叉树的第i层上至多有 2i-1 个结点(i>0) eg:第3层最多结点个数 2("#$)
性质2: 深度为k的二叉树至多有2k - 1个结点(k>0) eg: 层次2(") − 1= 7
性质3: 任意一棵二叉树,如果其叶结点数为N&,而度数为2的结点总数为N' ,则N& = N'+1
性质4: 最多有n个结点的完全二叉树的深度必为 log2(n+1)
性质5: 对完全二叉树,若从上至下、从左至右编号,则编号为i 的结点,其左孩子编号必为
2i,其右孩子编号必为2i+1 , 其父节点的编号必为i//2(i=1 时为根,除外)
![](https://img-blog.csdnimg.cn/direct/c22604db48844b399b258252cf214221.png)
广度优先遍历
广度优先可以找到最短路径:
相当于层次遍历,先把第1层给遍历完,看有没有终点;再把第2层遍历完,看有没有重点。
![](https://img-blog.csdnimg.cn/direct/d8c992dffed3440eb134ad4f5d45bdcb.png)
广度优先----插入节点
初始操作:
初始化队列、将根节点入队、准备加 入到二叉树的新结点
重复执行: 获得并弹出队头元素
1、若当前结点的左右子结点不为空,则将其左右子节点入队列
2、若当前结点的左右子节点为空,则将新结点挂到为空的左子结点、或者右子 节点
![](https://img-blog.csdnimg.cn/direct/9349514d567b4c90beeb521b3e036568.png)
深度优先遍历
三种遍历:
先序遍历:根左右
0 1 3 7 8 4 9 2 5 6
中序遍历:左根右
7 3 8 1 9 4 0 5 2 6
后序遍历:左右根
7 8 3 9 4 1 5 6 2 0
![](https://img-blog.csdnimg.cn/direct/64a97775db1c4dfcb53add9f53b7a636.png)
遍历结果反推结构
知道中序遍历和先序遍历或者后序遍历就可以推出二叉树的结构
思路:
通过先序遍历可以确定哪个元素是根节点,通过中序遍历可以知道左子树都有那些结
点、右子树都有那些结点。
1、有了树(先序、中序表示),根据先序确认根节点,中序确定左子树,右子树;有了
左子树和右子树,相当于2颗树
2、重复步骤1;直到划分完毕
代码实现
# 1.定义Node类,表示节点类
class Node:
# 初始化节点的信息
def __init__(self,item):
self.item = item # 元素域,数值域:存储区具体数据的
self.lchild = None # 链接域,地址域:左子节点
self.rchild = None # 链接域,地址域:右子节点
# 2.定义 BinaryTree类,表示:二叉树类
class BinaryTree:
# 2.1指定二叉树的根节点
def __init__(self,root=None):
self.root = root # 充当根节点
# 2.2 添加元素
def add(self,item):
"""
自定义二叉树添加元素
:param item: 要添加的数据
:return:
"""
# 1.判断根节点是否为空,若为空,直接将当前元素设置为:根节点,程序结束
if self.root == None:
self.root = Node(item)
return
# 2.走到这里,说明根节点不为空,我们准备列表,用于存储: 二叉树中所有的节点。
queue = []
queue.append(self.root)
# 3. 通过while True, 不断的获取到二叉树中的节点.
while True:
cur_node = queue.pop(0) # 获取节点的.
# 4. 判断当前节点的 左子树(左子节点)是否为空.
if cur_node.lchild == None:
# 4.1 若为空, 则将: 新节点添加为当前节点的 左子树
cur_node.lchild = Node(item)
return
else:
# 4.2 如果不为空, 则将: 当前节点的左子树加到 队列中.
queue.append(cur_node.lchild)
# 5. 判断当前节点的 右子树(右子节点)是否为空.
if cur_node.rchild == None:
# 5.1 若为空, 则将: 新节点添加为当前节点的 右子树
cur_node.rchild = Node(item)
return
else:
# 5.2 如果不为空, 则将: 当前节点的右子树加到 队列中.
queue.append(cur_node.rchild)
# 2.3 遍历广度优先
def breadth_travle(self):
# 1. 判断根节点是否为空.
if self.root == None:
return
# 2. 创建队列(queue), 用于存储: 二叉树的元素.
queue = []
queue.append(self.root) # 添加根节点到队列中.
# 3. 循环获取元素(节点), 只要队列不为空(说明还有二叉树节点), 就一直遍历.
while len(queue) > 0:
# 3.1 走这里, 说明队列有数据, 我们从(队头)获取元素.
node = queue.pop(0)
# 3.2 打印当前节点的内容.
print(node.item, end=' ')
# 3.3 判断当前节点是否有左子树, 有就添加到 队列中.
if node.lchild is not None:
queue.append(node.lchild)
# 3.4 判断当前节点是否有右子树, 有就添加到 队列中.
if node.rchild is not None:
queue.append(node.rchild)
# 2.4 遍历, 深度优先 => 前序, 即: 根, 左, 右
def preorder_travle(self, root): # root表示节点
# 1. 判断根节点是否不为空, 不为空, 就按照 根,左,右 顺序逐个获取.
if root is not None:
# 2. 根
print(root.item, end = ' ')
# 3. 左, 递归获取.
self.preorder_travle(root.lchild)
# 4. 右, 递归获取.
self.preorder_travle(root.rchild)
# 2.5 遍历, 深度优先 => 中序, 即: 左, 根, 右
def inorder_travle(self, root): # root表示节点
# 1. 判断根节点是否不为空, 不为空, 就按照 左, 根, 右 顺序逐个获取.
if root is not None:
# 2. 左, 递归获取.
self.inorder_travle(root.lchild)
# 3. 根
print(root.item, end = ' ')
# 4. 右, 递归获取.
self.inorder_travle(root.rchild)
# 2.6 遍历, 深度优先 => 后序, 即: 左, 右, 根
def postorder_travle(self, root): # root表示节点
# 1. 判断根节点是否不为空, 不为空, 就按照 左, 右, 根 顺序逐个获取.
if root is not None:
# 2. 左, 递归获取.
self.postorder_travle(root.lchild)
# 3. 右, 递归获取.
self.postorder_travle(root.rchild)
# 4. 根
print(root.item, end = ' ')
# 3.测试代码1,创建节点和二叉树
def test1():
# 3.1 创建节点
node = Node('乔峰')
# 3.2 打印节点
print(node.item)
# 3.3 创建二叉树对象
bt = BinaryTree(node)
print(bt) # 二叉树
print(bt.root) # 二叉树的根节点
print(bt.root.item) # 二叉树的根节点的元素域
# 4 测试代码2 :演示队列,先进先出
def test2():
# 4.1创建队列.
queue = []
# 4.2 往队列中(从队尾)添加元素
queue.append('A')
queue.append('B')
queue.append('C')
# 4.3 从队列中(从队头)获取元素。
print(queue.pop(0))
print(queue.pop(0))
print(queue.pop(0))
# 5.测试3:测试添加元素到二叉树中, 及广度优先遍历
def test3():
# 5.1 创建二叉树
bt = BinaryTree()
# 5.2 添加元素
bt.add('A')
bt.add('B')
bt.add('C')
bt.add('D')
bt.add('E')
bt.add('F')
bt.add('G')
bt.add('H')
bt.add('I')
bt.add('J')
bt.add('K')
# 5.3 广度优先遍历, 查看结果.
bt.breadth_travle()
# 6. 测试代码4: 测试添加元素到二叉树中, 及 深度优先遍历.
def test4():
# 5.1 创建二叉树.
bt = BinaryTree()
# 5.2 添加元素.
bt.add('0')
bt.add('1')
bt.add('2')
bt.add('3')
bt.add('4')
bt.add('5')
bt.add('6')
bt.add('7')
bt.add('8')
bt.add('9')
# 5.3 广度优先遍历, 查看结果.
# bt.breadth_travle() # 广度优先: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
# 5.4 深度优先, 前序
print('前序: ', end = '')
bt.preorder_travle(bt.root) # 前序: 0 1 3 7 8 4 9 2 5 6
print()
# 5.5 深度优先, 中序
print('中序: ', end = '')
bt.inorder_travle(bt.root) # 中序: 7 3 8 1 9 4 0 5 2 6
print()
# 5.6 深度优先, 后序
print('后序: ', end = '')
bt.postorder_travle(bt.root) # 后序: 7 8 3 9 4 1 5 6 2 0
# 6.main函数
if __name__ == '__main__':
#test1()
#test2()
#test3()
test4()