平衡二叉树(AVL树)
AVL树是一种二叉搜索树,并且每个节点的左右子树高度之差最多为1。AVL树是第一个在最坏的情况下保证以O(logn)的时间进行搜索,插入和删除操作的数据结构,AVL树能在对数时间内完成操作的主要思想是在插入和删除的时候花一些时间来保持树的平衡,使树的高度总在O(logn)范围内
插入后不满足AVL树的情况
令x是要插入AVL树种的关键字,首先将x插入树的底部,如果插入后仍是AVL树,则没有问题,否则要对数进行平衡。假设节点A的左子树和右子树在插入后失去平衡(高度差为2),这将分四种情况:
- 对A的左孩子的左子树进行了一次插入
- 对A的左孩子的右子树进行了一次插入
- 对A的右孩子的左子树进行了一次插入
- 对A的右孩子的右字树进行了一次插入
-
其中第一和第四种情形对称,第二和第三种情形对称,第一,四可以通过一次单旋转完成调整,
下图是其中两种,剩两种与它们右对称
- 图(a)插入新节点后,B树的高度是h+2,C树高度是h,为了保持树的平衡需要进行旋转,将B转到树顶,然后根据二叉搜索树的性质调整树的其他部分.
-
- 图(b)插入节点后,旋转一个位置不够,需要旋转两个位置. 首先对B进行顺时针旋转,然后对A作顺时针旋转
-
顺时针和逆时针旋转两种方式:
双旋转的方式
(首先对B进行逆时针旋转,然后对A进行顺时针旋转)
(首先对B进行顺时针旋转,然后对A进行逆时针旋转)
上面两个例子中 A被称作关键节点
关键节点: 它是插入操作之后非AVL树的最小树的根节点,在插入节点之前必须找到关键节点,从而判断是哪种情况。于是我们在每个节点中记录一个平衡因子,即左右子树的高度之差.对AVL树而言,任意一个节点的平衡因子只能是1,-1或0. 关键节点的平衡因子一定不是0,并且在平衡后高度与插入前相同
源代码namespace AVLTree
{
public class Node
{
public int Value;
public Node Left;
public Node Right;
public int Factor;
}
public class AVLTree
{
private Node root;
private Node ParentNode(int x)
{
Node node = root;
Node parent = null;
while (node != null)
{
if (node.Value == x)
{
return parent;
}
parent = node;
if (node.Value > x)
{
node = node.Left;
}
else
{
node = node.Right;
}
}
throw new Exception(string.Format("{0} has no parent", x));
}
public void Insert(int x)
{
Insert(ref root,x);
}
private void Insert(ref Node tree, int x)
{
Node node = new Node() { Value = x };
if (tree == null)
{
tree = node;
}
if (tree.Value > x)
{
Insert(ref tree.Left,x);
if (Depth(tree.Left) - Depth(tree.Right) == 2)
{
if (tree.Left.Value > x)
{
R_Rotate(tree);
}
else if (tree.Left.Value < x)
{
LR_Rotate(tree);
}
}
}
else if (tree.Value < x)
{
Insert(ref tree.Right,x);
if (Depth(tree.Right) - Depth(tree.Left) == 2)
{
if (tree.Right.Value < x)
{
L_Rotate(tree);
}
else if (tree.Right.Value > x)
{
RL_Rotate(tree);
}
}
}
}
public void L_Rotate(Node tree)
{
Node parent = ParentNode(tree.Value);
Node lr = tree.Right;
tree.Right = lr.Left;
lr.Left = tree;
if (parent != null)
{
if (Object.ReferenceEquals(parent.Left, tree))
{
parent.Left = lr;
}
else if (Object.ReferenceEquals(parent.Right, tree))
{
parent.Right = lr;
}
}
else
{
root = tree;
}
}
public void R_Rotate( Node tree)
{
Node parent = ParentNode(tree.Value);
Node lc = tree.Left;
tree.Left = lc.Right;
lc.Right = tree;
if (parent != null)
{
if (Object.ReferenceEquals(parent.Left, tree))
{
parent.Left = lc;
}
else if (Object.ReferenceEquals(parent.Right, tree))
{
parent.Right = lc;
}
}
else
{
root = lc;
}
}
public void LR_Rotate(Node tree)
{
L_Rotate(tree.Left);
R_Rotate(tree);
}
public void RL_Rotate(Node tree)
{
R_Rotate(tree.Right);
L_Rotate(tree);
}
private int Depth(Node tree)
{
if (tree == null) return 0;
else
{
int dleft = Depth(tree.Left);
int dright = Depth(tree.Right);
return (dleft > dright ? dleft + 1 : dright + 1);
}
}
public override string ToString()
{
return Tree(root);
}
private string Tree(Node node)
{
if (node == null)
{
return string.Empty;
}
string left = Tree(node.Left);
string right = Tree(node.Right);
if (!string.IsNullOrEmpty(left) || !string.IsNullOrEmpty(right))
{
return string.Format("{0}({1},{2})", node.Value, Tree(node.Left), Tree(node.Right));
}
else
{
return node.Value.ToString();
}
}
public static void Swap(ref int x, ref int y)
{
int temp = x;
x = y;
y = temp;
}
}
}