树广泛应用于计算机科学的多个领域,从操作系统、图形学、数据库到计算机网络。作为数据结构的树和现实世界中的树有很多共同之处,二者皆有根、枝、叶,不同之处在于,前者的根在顶部,而叶在底部。
一、树的定义
定义一:树由节点及连接节点的边构成。树有以下属性
- 有一个根节点;
- 除根节点外,其他每个节点都与其唯一的父节点相连;
- 从根节点到其他每个节点都有且仅有一条路径;
- 如果每个节点最多有两个节点,我们就称这样的树为二叉树
定义二:一棵树要么为空,要么由一个根节点和零棵或多棵子树构成,子树本身也是一棵树。每棵子树的根节点通过一条边连接到父树的根节点。
二、树的相关概念
- 节点:节点是树的基础部分,它可以有自己的名字,我们称作“键”。节点也可以带有附加信息,我们称作“有效载荷”;
- 边:边是树的另一个基础部分,两个节点通过一条边相连,表示他们之间存在关系。除了根节点之外,其他每个节点都仅有一条入边,出边则可能有多条;
- 根节点:根节点是树中唯一没有入边的节点;
- 路径:路径是由边连接的有序节点列表;
- 子节点:一个节点通过出边与子节点相连;
- 父节点:一个节点是其所有子节点的父节点;
- 兄弟节点:具有同一父节点的节点互称为兄弟节点;
- 子树:一个父节点及其所有后代的节点和边构成一棵子树;
- 叶子节点:叶子节点没有子节点;
- 层数:节点n的层数是从根节点到n的唯一路径长度;
- 高度:树的高度是其中节点层数的最大值。
三、树的实现
可以使用以下函数创建并操作二叉树
- BinaryTree()创建一个二叉树实例;
- getLeftChild()返回当前节点的左子节点所对应的二叉树;
- getRightChild()返回当前节点的右子节点所对应的二叉树;
- setRootVal(val)在当前节点中存储参数val中的对象;
- getRootVal()返回当前节点存储的对象;
- insertLeft(val)新建一棵二叉树,并将其作为当前节点的左子节点;
- insertRight(val)新建一棵二叉树,并将其作为当前节点的右子节点。
(1)列表之列表
用列表构建树时,我们将根节点的值作为列表的第一个元素;第二个元素代表左子树的列表;第三个元素代表右子树列表。
列表之列表表示法有个很好的性质,那就是表示子树的列表结构符合树的定义,这样的结构是递归的。
列表函数BinaryTree
def BinaryTree(r):
return [r, [], []]
该函数构造一个简单的列表,它仅有一个根节点和两个作为子节点的空列表。要添加左子树,需要在列表的第二个位置加入一个新列表,如果列表的第二个位置上已由内容,我们需要保留已有内容,并将其作为新列表的左子树。
插入左子树函数
def insertLeft(root, newBranch):
# 获取左子树
t = root.pop(1)
if len(t) > 1:
# 若存在左子树,则将其作为新节点的左子树插入列表
root.insert(1, [newBranch, t, []])
else:
# 若不存在左子树,则添加新节点即可
root.insert(1, [newBranch, [], []])
return root
插入右子树
def insertRight(root, newBranch):
# 获取右子树
t = root.pop(2)
if len(t) > 1:
# 如果存在右子树,则将作为新节点的右子树插入列表
root.insert(2, [newBranch, [], t])
else:
# 如果不存在,则添加新节点即可
root.insert(2, [newBranch, [], []])
return root
树的访问函数
# 获取根节点元素
def getRootVal(root):
return root[0]
# 设置根节点元素
def setRootVal(root, newVal):
root[0] = newVal
# 获取左子树
def getLeftChild(root):
return root[1]
# 获取右子树
def getRightChild(root):
return root[2]
(2)节点与引用
树的第二种表示法是利用节点与引用,我们定义一个类,其中有根节点和左右子树的属性。
“节点与引用”表示法的要点是,属性left和right会指向BinaryTree类的其他实例。
BinaryTree类
class BinaryTreee:
def __init__(self, rootObj):
self.key = rootObj
self.leftChild = None
self.rightChild = None
插入左子节点
def insertLeft(self, newNode):
if self.leftChild == None:
# 如果当前节点没有左子树,直接将其左子节点设置为新插入的节点即可
self.leftChild = BinaryTreee(newNode)
else:
# 如果当前节点有左子节点
# 先创建新节点
t = BinaryTreee(newNode)
# 将新节点的左子节点指向之前的左子节点
t.leftChild = self.leftChild
# 将当前节点的左子节点指向新节点
self.leftChild = t
插入右子节点
def insertRight(self, newNode):
if self.rightChild == None:
# 如果当前节点没有右子树,直接将其右子节点设置为新插入的节点即可
self.rightChild = BinaryTreee(newNode)
else:
# 如果当前节点没有右子节点
# 先创建新节点
t = BinaryTreee(newNode)
# 将新节点的右子树指向之前的右子节点
t.rightChild = self.rightChild
# 将当前节点的右子节点指向新节点
self.rightChild = t
二叉树的访问函数
# 获取右子树
def getRightChild(self):
return self.rightChild
# 获取左子树
def getLeftChild(self):
return self.leftChild
# 设置根节点元素
def setRootVal(self, obj):
self.key = obj
# 获取根节点元素
def getRootVal(self):
return self.key
本系列为《Python数据结构与算法分析》第二版学习笔记,作者:布拉德利.米勒;戴维.拉努姆。译:吕能, 刁寿钧