一.树与树算法
1.什么是树
树是哟总抽象数据类型,用来模拟具有树状结构性值的数据集合,它是由n(n>=1)个有限节点组成一个具有层次关系的集合,如下图所示:
它具有以下特点:
1)每个节点有零个或这多个子节点
2)没有父节点的节点成为根节点,如上图的节点1就是根节点
3)没有个非根节点有且只有一个父节点
4)除了根节点外,每个子节点可以分为多个不相交的子树
2.树的概念
节点的度:一个节点含有的子树的个数成为该节点的度;
树的度:一棵树中,最大的节点的度称为树的度,如上图树的度为2,因为最大的节点的度为2(节点2 和 节点3)
兄弟节点:拥有同一个父节点的子节点叫做兄弟节点
叶子节点:没有子节点的节点叫做叶子节点
3.二叉树的性质
1).一个节点最多只有两个子节点的树交二叉树
2).二叉树中,第 i 层最多有 2i-1 个结点。
3).如果二叉树的深度为 K,那么此二叉树最多有 2K-1 个结点。
4).二叉树中,终端结点数(叶子结点数)为 n0,度为 2 的结点数为 n2,则 n0=n2+1。
4.二叉树的分类
满二叉树
如果二叉树中除了叶子结点,每个结点的度都为 2,则此二叉树称为满二叉树
完全二叉树
如果二叉树中除去最后一层节点为满二叉树,且最后一层的结点依次从左到右分布,
则此二叉树被称为完全二叉树。
5.二叉树的创建
我们用pyhton代码创建一个二叉树
class Node(object):
"""
二叉树节点对象封装的类
"""
def __init__(self, element):
self.element = element
self.lchild = None
self.rchild = None
class Tree(object):
"""二叉树的封装"""
def __init__(self, root=None):
self.root = root
def add(self, item):
"""往二叉树里面添加元素"""
node = Node(item)
# #如果树是空的,则对根节点赋值
if not self.root:
self.root = node
else:
# 先找树的根节点, 存储到变量queue中
queue = []
queue.append(self.root)
while queue:
item = queue.pop(0)
#如果当前节点没有左孩节点,则把元素加入左孩节点
if not item.lchild:
item.lchild = node
return
#如果当前节点有左孩节点,没有右孩节点,把元素加入右节点
elif not item.rchild:
item.rchild = node
return
#如果当前节点即有左节点也有右节点,把这两个节点加入队列,重新进入while循环,判断这两个节点是否还有左右子节点,一直循环下去
else:
queue.append(item.lchild)
queue.append(item.rchild)
二. 二叉树的遍历
遍历是指对树中所有结点的信息的访问,即依次对树中每个结点访问一次且仅访问一次,我们把这种对所有节点的访问称为遍历。
遍历的模式分为深度优先和广度优先,如图所示:
我们以下图简单的二叉树为例,理解深度遍历优先与广度遍历优先:
1.广度优先遍历
广度优先遍历即层级遍历,逐层依次遍历,以上图为例,遍历顺序为 1—>2—>3—>4—>5—>6—>7,我们可以利用队列实现数的层次遍历
def breadth_travel(self):
if not self.root: #判断有无根节点,若无根结点即二叉树为空
return
else:
queue = [] #创建空列表,存储节点
queue.append(self.root) #首先将跟节点加入队列
while queue:
node = queue.pop(0) #从列表中弹出第一个节点
print(node.element, end=',')
if node.lchild: #此处的node为从列表中弹出的第一个节点,判断此节点有无左孩节点
queue.append(node.lchild) #若左孩节点存在,则加入队列
if node.rchild: #判断此节点有无右孩节点
queue.append(node.rchild) #若右孩节点存在,则加入队列
print()
2.深度优先遍历
深度优先遍历分为三类:先序遍历,中序遍历,后序遍历。
依然以上面简单的二叉树为例,三种遍历方法的遍历顺序如下:
先序遍历:1 2 4 5 3 6 7 (可简单看为从上到下,从左到右的不重复遍历)
#递归实现先序遍历
def preorder(self, root):
if root == None:
return
print(root.element, end=', ')
self.preorder(root.lchild)
self.preorder(root.rchild)
中序遍历:4 2 5 1 6 3 7 (可以简单看作根据数中节点的平面位置按从左到右依次遍历)
"""递归实现中序遍历"""
def inorder(self, root):
if root == None:
return
self.inorder(root.lchild)
print(root.element, end=', ')
self.inorder(root.rchild)
后续遍历:4 5 2 6 7 3 1 (可以看作从叶子节点开始从左到右,从下到上依次遍历)
#递归实现后序遍历
def preorder(self, root):
if root == None:
return
self.preorder(root.lchild)
self.preorder(root.rchild)
print(root.element, end=', ')
三. 二叉排序树
1.定义
二叉排序树,又叫二叉查找树,它或者是一棵空树;或者是具有以下性质的二叉树:
1.若它的左子树不空,则左子树上所有节点的值均小于它的根节点的值;
2.若它的右子树不空,则右子树上所有节点的值均大于它的根节点的值;
3.它的左右子树也分别为二叉排序树。
四. 二叉树遍历总结
1).某二叉树的前序序列和后序序列正好相反,则该二叉树一定是高度等于其节点数的二叉树。
解:前序遍历我们可以理解为 根-左-右,后序可以理解为左-右-根,若前序和后序相反,则该二叉树的任意结点必定没有左孩节点或者右孩节点,包括空节点和一个节点的情况,综上所述即就是高度等于其节点数的二叉树满足。
2)一个二叉树的先序遍历结果和中序遍历结果相同,则其所有非叶子节点必须满足的条件是只有右子树
解:前序遍历是从根节点开始,中序遍历从最左边的开始,若两个的遍历结果相同,则第一个必定是根节点,所以根节点不能有左子树,如果是三层二叉树,则第二层的节点也不能有左子树,所以每个非叶子节点必须没有左子树。