平衡二叉搜索树(Balanced Binary Tree):
是一种结构平衡的二叉搜索树,即叶节点高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。它能在O(log n)内完成插入、查找和删除操作,最早被发明的平衡二叉搜索树为AVL树。
常见的平衡二叉搜索树有:AVL树、红黑树、Treap、节点大小平衡树。
注意:移动树的节点时,被移动节点及其原新两个位置的父、子节点的指向均需重新指向,保证各节点指向正确。
平衡二叉搜索树(AVL树),可以自动进行调整,以确保树时时保持平衡。
平衡因子(balance factor):为实现AVL树,需要在树的每个节点加入一个平衡因子(balance factor)以跟踪其变化情况。
一个节点的平衡因子为其左子树的高度和右子树的高度之差,即balanceFactor=height(leftSubTree)−height(rightSubTree)。
如果平衡因子大于零,则子树左重(left-heavy)。如果平衡因子小于零,则子树右重(right-heavy)。如果平衡因子是零,那么树完美平衡。
为实现AVL树,定义平衡因子为-1、0或1时这个树是平衡的,一旦树的节点的平衡因子超出了这个范围,则需要将树恢复平衡。
此例与BST二叉查找树的代码区别:
1、TreeNode类中,__init__多了balanceFactor属性;
2、BinarySearchTree类中,_put()中多了2行更新平衡因子的代码;
3、BinarySearchTree类中,多了updateBalance()、rotateLeft()、rotateRight()、rebalance()四个函数;
4、此例中删除节点时的平衡未实现。
示例:
# 创建树的节点类
class TreeNode(object):
# 初始化树的节点
def __init__(self, key, val, left=None, right=None, parent=None, balanceFactor=0):
self.key = key #节点值,节点位置,索引
self.payload = val #有效载荷,节点显示的值
self.leftChild = left #左子节点
self.rightChild = right #右子节点
self.parent = parent #父节点
self.balanceFactor = balanceFactor #节点的平衡因子
# 判断是否有左子节点,若有则返回左子节点
def hasLeftChild(self):
return self.leftChild
# 判断是否有右子节点,若有则返回右子节点
def hasRightChild(self):
return self.rightChild
# 判断是否是左子节点(父节点存在,并且self与self父节点的左子节点相同)
def isLeftChild(self):
# 下面的含义是(self.parent is not None) and (self.parent.leftChild == self)
return self.parent and self.parent.leftChild == self
# 判断是否是右子节点
def isRightChild(self):
return self.parent and self.parent.rightChild == self
# 判断是否是根节点
def isRoot(self):
return not self.parent #没有父节点
# 判断是否是叶节点
def isLeaf(self):
return not (self.rightChild or self.leftChild) #没有左右子节点
# 判断是否有子节点
def hasAnyChildren(self):
return self.rightChild or self.leftChild #有左或右子节点
# 判断是否有2个子节点
def hasBothChildren(self):
return self.rightChild and self.leftChild #有左右2个子节点
# 替换节点数据
def replaceNodeData(self, key, value, lc, rc):
self.key = key #更新节点值
self.payload = value #更新有效载荷
self.leftChild = lc #更新左子节点
self.rightChild = rc #更新右子节点
if self.hasLeftChild(): #若有左子节点
self.leftChild.parent = self #将该节点的左子节点的父节点指向self
if self.hasRightChild(): #若有右子节点
self.rightChild.parent = self #将该节点的右子节点的父节点指向self
# 中序遍历
# 只要用了yield语句,普通函数就是生成器,也是迭代器,在定义过程中不需要像迭代器那样写__iter__()和__next__()方法。yield语句的作用就是在调用的时候返回相应的值和作为生成器的标志。
def __iter__(self):
if self: #若当前节点存在,则
if self.hasLeftChild(): #若当前节点有左子节点,则
for elem in self.leftChild: #循环输出当前节点的左子树的节点值
yield elem #在for循环中,每次执行到yield时,就返回一个迭代值,且不会终止循环;下个循环时,代码从yield返回值的下一行继续返回
yield self.key #返回当前节点值
if self.hasRightChild(): #若当前节点有右子节点,则
for elem in self.rightChild: #循环输出当前节点的右子树的节点值
yield elem
# 将被删除节点的继任者拼接到被删除的节点位置
def spliceOut(self):
if self.isLeaf(): #若被删除节点是叶节点,则无