树结构在计算机领域使用十分广泛。在操作系统源程序中,树和森林被用来构造文件系统。我们看到的window和linux等文件管理系统都是树型结构。在编译系统中,如C编译器源代码中,二叉树的中序遍历形式被用来存放C 语言中的表达式。在游戏设计领域,许多棋类游戏的步骤都是按树型结构编写。这一篇我们就来了解下树,并实现一下最基本的二叉树。
树
树(tree),和我们熟悉的顺序表一样,也是一种抽象的数据结构。不过顺序表是依次首尾相连,而树代表的是一对多的对应关系。如下图所示,是Linux的文件系统的一部分,典型的树形结构
其结构有点像倒挂的树,根在上,叶在下。其具有如下几个特点
- 每个节点有0个或多个子节点
- 没有父节点的节点称为根节点
- 每一个非根节点有且仅有一个父节点
- 除了根节点,每个子节点可以分为多个不相交的子树
同时还有一些术语要了解下
- 节点的度 - 一个节点含有的子树个数称为该节点的度,例如上面
root
节点的度为4 - 树的度 - 一棵树中最大的节点的度称为树的度,上面树的度为4
- 叶节点 - 度为0的节点
- 兄弟节点 - 具有相同父节点的节点互称兄弟节点
- 节点的层次 - 从根节点开始,根为第一层,其子节点为第二层,以此类推
- 树的深度或高度 - 树中节点的最大层次,上面树的高度为3
树的物理存储
上面说的是树的逻辑结构,下面看下物理存储结构。
顺序表存储
从根一直到页,逐层从左到右放进顺序表。例如上面的树就会如下存放
['root','etc','home','var','proc','issue','passwd'...]
链表存储
链表方式,每个节点除了存储自身的内容,还有存储其子节点的地址。这种方式比较普遍。
二叉树
因为有发散关系,树的结构可以很复杂,我们只研究比较有规律的典型结构,二叉树。
二叉树(binary tree),的每个节点最多含有两个子树,例如下图
二叉树还有几种特殊形式
- 完全二叉树 - 除了最后一层,其他层的节点数都已经达到了最大值,且最后一层的的所有节点从左到右连续紧密排列,上面就是一个完全二叉树
- 满二叉树 - 所有叶节点都在最下一层的完全二叉树称为满二叉树,上面的树不是满二叉树
- 平衡二叉树 - 任何节点的两颗子树高度差不超过1的二叉树
二叉树代码实现
下面用代码实现二叉树,并完成添加节点,遍历节点两种操作。这里的添加结点采用从左至右,每层所有子节点添加完毕以后再添加下一层的方式。而遍历节点又会有深度优先和广度优先这两种区别。
下面我们依次来看。
节点类
采用链表方式存储的节点类如下
class Node:
"""binary tree node"""
def __init__(self, value, lchild=None, rchild=None):
self.value = value
self.lchild = lchild
self.rchild = rchild
每个节点除了存储自身的值,还通过self.lchild
和self.rchild
分别存储左节点和右节点的地址。默认地址都是None
,表示没有子节点。
树类
树类在初始的时候只需要有一个根节点的地址即可
class Binary_Tree:
"""binary tree"""
def __init__(self, root=None):
self.root = root
默认不带参数的初始是一个空树。
添加节点
添加节点采取从左至右每层依次添加的顺序,每层填满了再添加到下一层。
根据树的特性,这时候可以利用一个小技巧,就是利用队列的方式,首先把根节点放入队列,从列表中读取节点的时候就将该节点的子节点从左至右依次放入队列中,有点类似于前面说到的顺序表存储结构。一直读取到某个节点的子节点有一个或都不存在时,将新的节点做为该节点的子节点。
temp = [self.root]
while temp:
nextNode = temp.pop(0)
if nextNode.lchild is None:
nextNode.lchild = node
return
elif nextNode.rchild is None:
nextNode.rchild = node
return
else:
temp.append(nextNode.lchild)
temp.append(nextNode.rchild)
从临时列表的尾部放元素,从头部取元素,达到队列的效果。下面考虑下特殊情况,就是树为空的情况,直接把新的节点做为根节点即可,于是完整实现如下
def add(self, node):
if self.root is None:
self.root = node
return
temp = [self.root]
while temp:
nextNode = temp.pop(0)
if nextNode.lchild i