平衡二叉树(AVL)
上一篇讲了 二叉搜索树
二叉搜索树的 查询、插入、删除 时间复杂度都为 O(logN)
这是一个理想状态
在非理想状态下,二叉搜索树的时间复杂度将会降低为 O(N),数组级别
假如我一组数据顺序为:1、2、3、4、5、6
然后按顺序将数据插入到 二叉搜索树,将构建成如下线性结构二叉树
那么此时 查询、插入、删除 时间复杂度将会降低为 O(N)
那么二叉搜索树的优势将消失
那么如何解决如上问题呢
我们需要引入平衡二叉树(AVLTree)
平衡二叉树的本质也是一颗二叉搜索树,不过对树做了限制
平衡二叉树限制如下
1:平衡二叉树本身是一个二叉搜索树
2:平衡二叉树中所有节点的左右子树的高度差 小于等于1(称之为平衡因子)
如上图中节点 1 的左子树高度为 0,右子树高度为 6
大于平衡因子 1 的限制,所以它不是一颗平衡二叉树
将上面数据按顺序插入到平衡二叉树看结果
平衡二叉树导致不平衡的两个操作:插入、删除
平衡二叉树失衡有如下四种情况
LL 型:也称作左左型,在破坏节点的左边的左边插入而导致失衡
如何判断属于什么型:从被破坏的节点开始数两个,下图中红色路径就是判断路径
LR 型:也称 左右型,在破坏节点的左边的右边插入而导致失衡
RL 型:也称右左型,在破坏节点的右边的左边插入而导致失衡
RR 型:也称右右型,在破坏节点的右边的右边插入而导致失衡
当失去平衡时,需要确定是那种类型导致的,然后做相应的旋转操作,将树恢复到平衡状态
C#实现代码如下
/// <summary>
/// 平衡二叉搜索树
/// </summary>
/// <typeparam name="T"></typeparam>
class AVLTree<T> : BSTree<T> where T : IComparable<T>
{
/// <summary>
/// 插入
/// </summary>
public override BinNode<T> Insert(T t)
{
BinNode<T> node = Search(t);
if (null != node)
{
return node;
}
//按照二叉搜索树的方式将值插入
node = Insert(t, _hot);
// 一:从 BinNode<T> g = _hot节点(新插入节点的父节点)开始,
// 二:如果节点 g 不平衡则旋转 g,使 g 平衡,到此结束
// 三:令 g = g.ParentNode 跳转到 二 继续执行
// 因为插入新节点只会导致一个节点失衡,所以一旦找到一个
// 不平衡的节点,使之平衡后则树恢复平衡,结束退出
for (BinNode<T> g = _hot; null != g; g = g.ParentNode)
{
if (!AvlBalanced(g))
{
if (g.IsRoot())
{
Root = RotateAt(TallerChild(TallerChild(g)));
}
else if (g.IsLChild())
{
g.ParentNode.LeftChild = RotateAt(TallerChild(TallerChild(g)));
UpdateHeightAbove(g.ParentNode.LeftChild);
}
else
{
g.ParentNode.RightChild = RotateAt(TallerChild(TallerChild(g)));
UpdateHeightAbove(g.ParentNode.RightChild);
}
break;
}
else
{
UpdateHeight(g);
}
}
return node;
}
/// <summary>
/// 删除
/// </summary>
public override bool Remove(T t)
{
BinNode<T> node = Search(t);
if (null == node)
{
return false;
}
// 按照二叉搜索树删除节点
Remove(node, ref _hot);
// 一:从 BinNode<T> g = _hot节点(新插入节点的父节点)开始,
// 二:如果节点 g 不平衡则旋转 g,使节点 g 平衡。
// 三:令 g = g.ParentNode,跳转到 二 继续执行
// 删除节点后失衡比较复杂,因为删除一个节点后可能会导致一
// 个节点失衡,旋转使其平衡后可能会导致其父节点再次失衡,
// 最坏情况会导致每次调整后其父节点会再次的失衡,直到跟节
BinNode<T> g = _hot;
while(null != g) //从_hot出发向上,逐层检查各代祖先g
{
if (!AvlBalanced(g)) //一旦发现g失衡,则(采用“3 + 4”算法)使之复衡,并将该子树联至
{
if (g.IsRoot())
{
Root = RotateAt(TallerChild(TallerChild(g))); //原父亲
g = Root;
}
else if (g.IsLChild())
{
g.ParentNode.LeftChild = RotateAt(TallerChild(TallerChild(g))); //原父亲
g = g.ParentNode.LeftChild;
}
else
{
g.ParentNode.RightChild = RotateAt(TallerChild(TallerChild(g))); //原父亲
g = g.ParentNode.RightChild;
}
}
else
{
UpdateHeight(g);
}
g = g.ParentNode;
}
return true;
}
/// <summary>
/// 理想平衡
/// </summary>
public bool Balanced(BinNode<T> node)
{
return NodeHeight(node.LeftChild) == NodeHeight(node.RightChild);
}
/// <summary>
/// 平衡因子
/// </summary>
public int BalancedFactor(BinNode<T> node)
{
return NodeHeight(node.LeftChild) - NodeHeight(node.RightChild);
}
/// <summary>
/// AVL 平衡条件
/// </summary>
public bool AvlBalanced(BinNode<T> node)
{
return -1 <= BalancedFactor(node) && BalancedFactor(node) <= 1;
}
// 在 左、右 孩子中取更高者
protected BinNode<T> TallerChild(BinNode<T> node)
{
int balFac = BalancedFactor(node);
if (balFac > 0) // 左高
{
return node.LeftChild;
}
else if (balFac < 0) // 右高
{
return node.RightChild;
}
else // 等高:与父亲x同侧者
{
return node.IsLChild() ? node.LeftChild : node.RightChild;
}
}
}