平衡二叉树的是指左右子树的高度相差不超过1的二叉查找树,要实现平衡二叉树,我们只要在二叉查找树插入结点的时候保证左右子树的高度相差不超过1即可。
一. 平衡二叉树的插入。
现在考虑两种情况:
1. 插入新的结点后树还满足平衡二叉树的性质,也就是说左右子树的高度差不超过1,那么我们只需要根据现在的左右子树情况设置一下树的状态即可,也就是现在是左子树高或者是右子树高,还是左右子树的高度相等。
2. 插入新的结点后树的子树高度差变成了2,那么现在树已经不满足平衡二叉树的性质了,所以需要调整树的结点,也就是需要对树进行旋转。
我们现在考虑2的情况下,树应该怎么旋转。
我们先看插入结点后,树的平衡情况(假设新节点是插入到了右子树,用right_tree表示):
case1:right_tree的右子树高
插入结点后,right_tree的右子树比左子树要高,那么我们就要向左旋转,看下图:
通过向左旋转后,树重新达到了平衡,之前的root结点变成了左结点,right_tree上升为跟结点。
case2:right_tree的左子树高
插入结点后,right_tree的左子树要比右子树高,这个情况比较复杂,树需要旋转两次才可以重新达到平衡,看下图:
right_tree先向右旋转一次,sub_tree上升一级,right_tree成为sub_tree的右子结点,然后跟结点再左旋转一次,最后sub_tree上升为跟结点,root变为左子结点,right_tree还是右子结点,但是sub_tree原先的左右子树T2和T3分别变成了root的右子树和right_tree的左子树。
case3:right_tree的左右子树高度相等
这种情况不可能存在,因为如果right_tree的左右子树高度相等,说明插入新节点后right_tree的高度没有发生变化,这和root的左右子树高度已经相差2矛盾。
下面是实现的核心代码:
template<class Record>
Error_code AVL_tree<Record>::insert(const Record &new_data)
{
bool taller;
return avl_insert(root,new_data,taller);
}
template<class Record>
Error_code AVL_tree<Record>::avl_insert(AVL_node<Record> *&sub_root, const Record &new_data, bool &taller)
{
if (sub_root == NULL)
{
sub_root = new AVL_node<Record>(new_data);
taller = true;
return success;
}
else if (new_data == sub_root->data)
{
taller = false;
return duplicate_error;
}
else if (new_data < sub_root->data)
{
avl_insert(sub_root->left, new_data, taller);
if (taller == true)
{
switch(sub_root->get_balance())
{
case left_higher:
left_balance(sub_root);
taller = false;
break;
case equal_height:
sub_root->set_balance(left_higher);
break;
case right_higher:
sub_root->set_balance(equal_height);
taller = false;
break;
}
}
}
else
{
avl_insert(sub_root->right, new_data, taller);
if (taller == true)
{
switch(sub_root->get_balance())
{
case left_higher:
sub_root->set_balance(equal_height);
taller = false;
break;
case equal_height:
sub_root->set_balance(right_higher);
break;
case right_higher:
right_balance(sub_root);
taller = false;
break;
}
}
}
}
template<class Record>
void AVL_tree<Record>::left_balance(AVL_node<Record> *&sub_root)
{
AVL_node<Record> *&left_tree = sub_root->left;
switch(left_tree->get_balance())
{
case left_higher:
sub_root->set_balance(equal_height);
left_tree->set_balance(equal_height);
rotate_right(sub_root);
break;
case equal_height:
cout << "impossible case" << endl;
break;
case right_higher:
AVL_node<Record> *sub_tree = left_tree->right;
switch(sub_tree->get_balance())
{
case equal_height:
sub_root->set_balance(equal_height);
left_tree->set_balance(equal_height);
break;
case left_higher:
sub_root->set_balance(right_higher);
left_tree->set_balance(equal_height);
break;
case right_higher:
sub_root->set_balance(equal_height);
left_tree->set_balance(left_higher);
break;
}
sub_tree->set_balance(equal_height);
rotate_left(left_tree);
rotate_right(sub_root);
break;
}
}
template<class Record>
void AVL_tree<Record>::right_balance(AVL_node<Record> *&sub_root)
{
AVL_node<Record> *&right_tree = sub_root->right;
switch(right_tree->get_balance())
{
case right_higher:
sub_root->set_balance(equal_height);
right_tree->set_balance(equal_height);
rotate_left(sub_root);
break;
case equal_height:
cout << "impossible case" << endl;
break;
case left_higher:
AVL_node<Record> *sub_tree = right_tree->left;
switch(sub_tree->get_balance())
{
case equal_height:
sub_root->set_balance(equal_height);
right_tree->set_balance(equal_height);
break;
case left_higher:
sub_root->set_balance(equal_height);
right_tree->set_balance(right_higher);
break;
case right_higher:
sub_root->set_balance(left_higher);
right_tree->set_balance(equal_height);
break;
}
sub_tree->set_balance(equal_height);
rotate_right(right_tree);
rotate_left(sub_root);
break;
}
}
template<class Record>
void AVL_tree<Record>::rotate_left(AVL_node<Record> *&sub_root)
{
AVL_node<Record> *right_tree = sub_root->right;
sub_root->right = right_tree->left;
right_tree->left = sub_root;
sub_root = right_tree;
}
template<class Record>
void AVL_tree<Record>::rotate_right(AVL_node<Record> *&sub_root)
{
AVL_node<Record> *left_tree = sub_root->left;
sub_root->left = left_tree->right;
left_tree->right = sub_root;
sub_root = left_tree;
}