1.树基础
官方定义:树是n(n>=0)个结点的有限集。在任意一棵非空树中:
- 有且仅有一个特定的被称为根(Root)的结点
- 当n>1时,其余结点可分为m(m>0)个互不相交的有限集T1,T2,…,Tm,其中每一个集合本身又是一棵树,并且称为根的子树(SubTree)
解释:
树是一种以层次化方式组织和存放数据的特定数据结构。树有两个主要特征:
- 每个项都有多个子节点
- 除了叫做根的特殊的项,所有其他的项都只有一个父节点
结点分类:
- 结点的度(Degree):结点拥有的子树数称为结点的度。度为0的结点称为叶子(Leaf)或终端结点。度不为0的结点称为非终端结点或分支结点
- 树的度:是树内各结点的度的最大值
结点间关系:
- 孩子和双亲:结点的子树的根称为该结点的孩子(Child),相应地,该结点称为孩子的双亲(Parent)
- 兄弟:同一个双亲的结点的孩子之间互称兄弟
结点的层次(Level):是从根结点开始计算起,根为第一层,根的孩子为第二层,依次类推。树中结点的最大层次称为树的深度(Depth)或高度
如果将树中结点的各子树看成从左至右是有次序的(即不能互换),则称该树为有序树,否则称为无序树。
森林:由m(m>=0)棵互不相交的树组成的集合
2.二叉树基础
官方定义:二叉树是n个结点的有限集合,该集合或者为空集,或者由一个根结点和两棵互不相交的、分别称为根结点的左子树和右子树的二叉树组成
解释: 二叉树(Binary Tree)是一种特殊的树型结构,它的特点是每个结点至多有两棵子树,且二叉树的子树有左右之分,其次序不能任意颠倒
思考:只有三个结点的树有多少种形态?
特殊的二叉树:
- 满二叉树:
-
完全二叉树:
对一棵具有n个结点的二叉树按层序编号,如果编号为i的结点与同样深度的满二叉树中编号结点为 i的结点在二叉树中位置完全相同,则这棵二叉树成为完全二叉树
其特点为:- 叶子结点只能出现在最下两层
- 最下层的叶子一定集中在左部连续位置
- 倒数二层,若有叶子结点,一定都在右部连续位置
- 如果结点度为1,则该结点只有左孩子,即不存在只有右子树的情况
- 同样结点数的二叉树,完全二叉树的深度最小
二叉树性质:
二叉树的存储方式:
- 链式存储:
- 顺序存储:
3.二叉树基本操作
class Node(object):
def __init__(self, item):
self.item = item
self.left = None #左结点指针
self.right = None #右结点指针
def __str__(self): #方便打印
return str(self.item)
class Tree(object):
def __init__(self):
# 根节点定义为 root 永不删除,做为哨兵使用。
self.root = Node('root')
3.1插入结点
插入一个元素(逐层向下插入):
def add(self, item):
node = Node(item)
if self.root is None: #边界条件
self.root = node
else:
q = [self.root] #队列:先进先出
while True:
pop_node = q.pop(0)
if pop_node.left is None:
pop_node.left = node
return
elif pop_node.right is None:
pop_node.right = node
return
else:
q.append(pop_node.left)
q.append(pop_node.right)
3.2二叉树遍历
二叉树的遍历,指的是如何按某种搜索路径巡防树中的每个结点,使得每个结点均被访问一次,而且仅被访问一次。
⼆叉树主要有两种遍历⽅式:
- 深度优先遍历:先往深⾛,遇到叶⼦节点再往回⾛。
- ⼴度优先遍历:⼀层⼀层的去遍历。
3.2.1 深度优先遍历
- 前序遍历:根-左-右
操作定义为:若二叉树为空,为空操作;否则(1)访问根节点;(2)先序遍历左子树;(3)先序遍历右子树。
def preorder(self, root): # 先序遍历
if root is None:
return []
result = [root.item]
left_item = self.preorder(root.left) #递归调用
right_item = self.preorder(root.right)
return result + left_item + right_item #根结点 左子树结点 右子树结点
- 中序遍历:左-根-右
操作定义为:若二叉树为空,为空操作;否则(1)中序遍历左子树;(2)访问根结点;(3)中序遍历右子树。
def inorder(self, root): # 中序序遍历
if root is None:
return []
result = [root.item]
left_item = self.inorder(root.left)
right_item = self.inorder(root.right)
return left_item + result + right_item #左 根 右
- 后序遍历:左-右-根
操作定义为:若二叉树为空,为空操作;否则(1)后序遍历左子树;(2)后序遍历右子树;(3)访问根结点。
def postorder(self, root): # 后序遍历
if root is None:
return []
result = [root.item]
left_item = self.postorder(root.left)
right_item = self.postorder(root.right)
return left_item + right_item + result #左 右 根
总结:
3.2.2 广度优先遍历
- 层序遍历:
操作定义为:若二叉树为空,为空操作;否则从上到下、从左到右按层次进行访问。
def traverse(self): # 层次遍历
if self.root is None:
return None
q = [self.root]
res = [self.root.item]
while q != []:
pop_node = q.pop(0)
if pop_node.left is not None:
q.append(pop_node.left)
res.append(pop_node.left.item)
if pop_node.right is not None:
q.append(pop_node.right)
res.append(pop_node.right.item)
return res
测试一下:
if __name__ == '__main__':
t = Tree()
for i in range(10): #10个结点
t.add(i)
print('层序遍历:', t.traverse())
print('先序遍历:', t.preorder(t.root))
print('中序遍历:', t.inorder(t.root))
print('后序遍历:', t.postorder(t.root))
层序遍历: ['root', 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
先序遍历: ['root', 0, 2, 6, 7, 3, 8, 9, 1, 4, 5]
中序遍历: [6, 2, 7, 0, 8, 3, 9, 'root', 4, 1, 5]
后序遍历: [6, 7, 2, 8, 9, 3, 0, 4, 5, 1, 'root']
总的程序如下:
#二叉树操作
class Node(object):
def __init__(self, item):
self.item = item
self.left = None #左结点指针
self.right = None #右结点指针
def __str__(self): #方便打印
return str(self.item)
class Tree(object):
def __init__(self):
# 根节点定义为 root 永不删除,做为哨兵使用。
self.root = Node('root')
def add(self, item):
node = Node(item)
if self.root is None: #边界条件
self.root = node
else:
q = [self.root] #队列:先进先出
while True:
pop_node = q.pop(0)
if pop_node.left is None:
pop_node.left = node
return
elif pop_node.right is None:
pop_node.right = node
return
else:
q.append(pop_node.left)
q.append(pop_node.right)
def traverse(self): # 层次遍历
if self.root is None:
return None
q = [self.root]
res = [self.root.item]
while q != []:
pop_node = q.pop(0)
if pop_node.left is not None:
q.append(pop_node.left)
res.append(pop_node.left.item)
if pop_node.right is not None:
q.append(pop_node.right)
res.append(pop_node.right.item)
return res
def preorder(self, root): # 先序遍历
if root is None:
return []
result = [root.item]
left_item = self.preorder(root.left) #递归调用
right_item = self.preorder(root.right)
return result + left_item + right_item #根结点 左子树结点 右子树结点
def inorder(self, root): # 中序序遍历
if root is None:
return []
result = [root.item]
left_item = self.inorder(root.left)
right_item = self.inorder(root.right)
return left_item + result + right_item #左 根 右
def postorder(self, root): # 后序遍历
if root is None:
return []
result = [root.item]
left_item = self.postorder(root.left)
right_item = self.postorder(root.right)
return left_item + right_item + result #左 右 根
if __name__ == '__main__':
t = Tree()
for i in range(10): #10个结点
t.add(i)
print('层序遍历:', t.traverse())
print('先序遍历:', t.preorder(t.root))
print('中序遍历:', t.inorder(t.root))
print('后序遍历:', t.postorder(t.root))
推导遍历结果: