平衡二叉树是一棵合理的二叉排序树
解释
对于这么一个序列

如果按照普通的排序思路,5>4>3>2>1,会得到这么一棵树

如果想要查询结点5,则需要比对很多次;
而如果以3为根,则可以得到一棵较为合理的树

这样就搜索结点5只需要3次即可
为了实现较为合理的排序,AVL就因此诞生
平衡二叉树有个至关重要的特点:
左右子树高度差不超过
1
由此减少树的深度,从而减少查找次数
通过**失衡树的根节点root和导致树失衡的结点node**来调整新的树
而根据2个方向来选择调整方法
node在root的哪一侧node在root孩子结点的哪一侧调整方法
RR:
// 代码的实现则是反过来,先连接原有左子树到现有左子树的右子树,再连接到中间节点的右子树
root 1 node/child 3
root->right_child = child->left_child;
child->left_child = root;
对于开头提到的序列

进行正常排序

可见,root是1, node是3
node在root的右侧:Rnode在root孩子节点的右侧:R两个都是R
进行调整

如果2原先有左子树,调整:

注意:如果遇到多棵树不平衡,则调整最小树
将上面的序列继续排序

排序

如图,有两棵树失衡,一棵树最大的树12345,一颗是345,我们只用调整最小的345即可
这棵也是RR,直接调整

和RR完全相反
LL:
// 代码的实现则是反过来,先连接原有左子树到现有左子树的右子树,再连接到中间节点的右子树
root 5 node/child 3
root->left_child = child->right_child;
child->right_child = root;
再来一组数据

正常排序

进行LL排序

继续

继续排序最小树

LR:
总结
RRLL// 代码的实现则是反过来
root 7 node/child 6
root->left_child = child->right_child; child-right_>child = root; //有右子树
root->left_child->right_child = child->left_child; root->left_child->right_child = child->left_child //有左子树
child->right_child = root;
root = child;

进行正常排序

两棵树失衡

调整最下面的树
可见,root是7, node是6
node在root的左侧:Lnode在root孩子节点的右侧:R即LR
进行调整

RL:
总结
LLRR// 代码的实现则是反过来
root 1 node/child 6
root->right_child->left_child = child->right_child; child-right_>child = root->right_child; //有右子树
root->right_child = child->left_child; child->left_child = root; //有左子树
child->left_child = root;
root = child;

进行正常排序

已经失衡,进行调整
可见,root是1, node是6
node在root的左侧:Rnode在root孩子节点的右侧:L即RL
进行调整

然后继续插入7/10

height字段来标记当前树的高度只实现二叉排序树,还未使用字段height
#include
using namespace std;
//节点
typedef struct TreeNode {
int data;
int height;
struct TreeNode* left_child;
struct TreeNode* right_child;
}TreeNode;
//进行二叉排序树的构建
void AVLInsert(TreeNode** T, int data)
{
if (*T == NULL) //没有节点
{
*T = (TreeNode*)malloc(sizeof(TreeNode)); //创建一个
(*T)->data = data;
(*T)->height = 0; //高度设为0
(*T)->left_child = NULL;
(*T)->right_child = NULL;
}
else if (data < (*T)->data)
{
AVLInsert(&(*T)->left_child, data); //比根节点的data大,插入在左子树
}
else if (data > (*T)->data)
{
AVLInsert(&(*T)->right_child, data);
}
}
//前序遍历打印树
void PreOrder(TreeNode* T)
{
if (T)
{
cout << T->data;
PreOrder(T->left_child); //递归调用左子树
PreOrder(T->right_child); //递归调用右子树
}
}
int main()
{
TreeNode* T = NULL;
int nums[5] = { 1,2,3,4,5 };
for (int i = 0; i < 5; i++)
{ //构建树
AVLInsert(&T, nums[i]);
}
PreOrder(T);
cout << endl;
return 0;
}

height字段可以直接调用,但为了易读我这里创建一个函数得到height)//获取高度高度
int GetHeight(TreeNode* node)
{
return node ? node->height : 0; //节点不为空,则返回节点的height值,否则返回0
}
获取最大高度
//获取最大高度
int GetMax(int a, int b)
{
return a > b ? a : b;
}
实现RR和LL
//RR旋转
void rrRotation(TreeNode* root, TreeNode** node)
{
TreeNode* tmp = root->right_child;
root->right_child = tmp->left_child; //原有左子树连接到现有左子树的右子树上
tmp->left_child = root; //使其父节点成为其现有的左子树
root->height = GetMax(GetHeight(root->left_child), GetHeight(root->right_child)) + 1;
tmp->height = GetMax(GetHeight(tmp->left_child), GetHeight(tmp->right_child)) + 1;
*node = tmp;
}
//LL旋转
void llRotation(TreeNode* root, TreeNode** node)
{
TreeNode* tmp = root->left_child;
root->left_child = tmp->right_child; //原有右子树连接到现有右子树的左子树上
tmp->right_child = root; //使其父节点成为其现有的右子树
root->height = GetMax(GetHeight(root->left_child), GetHeight(root->right_child)) + 1;
tmp->height = GetMax(GetHeight(tmp->left_child), GetHeight(tmp->right_child)) + 1;
*node = tmp;
}
实现LR和RL,就是调用LL和RR
//LR
void lrTotation(TreeNode** T)
{
rrRotation((*T)->left_child, &(*T)->left_child);
llRotation(*T, T);
}
//RL
void rlTotation(TreeNode** T)
{
llRotation((*T)->right_child, &(*T)->right_child);
rrRotation(*T, T);
}
最后完善构建二叉树
//进行二叉排序树的构建
void AVLInsert(TreeNode** T, int data)
{
if (*T == NULL) //没有节点
{
*T = (TreeNode*)malloc(sizeof(TreeNode)); //创建一个
(*T)->data = data;
(*T)->height = 0; //高度设为0
(*T)->left_child = NULL;
(*T)->right_child = NULL;
}
else if (data < (*T)->data) //比根节点的data小,插入在左子树 :L
{
AVLInsert(&(*T)->left_child, data);
//获取当前节点左右子树的高度
int left_height = GetHeight((*T)->left_child);
int right_height = GetHeight((*T)->right_child);
//判断高度差
if (left_height - right_height > 1)
{
if (data < (*T)->left_child->data)//小于父节点左子树的值,说明在左边 :L
{
//LL
llRotation(*T, T);
}
else// : R
{
//LR
lrTotation(T);
}
}
}
else if (data > (*T)->data)//比根节点的data大,插入在右子树 :R
{
AVLInsert(&(*T)->right_child, data);
//获取当前节点左右子树的高度
int left_height = GetHeight((*T)->left_child);
int right_height = GetHeight((*T)->right_child);
//判断高度差
if (right_height - left_height > 1)
{
if (data > (*T)->right_child->data) //大于父节点右子树的值,说明在右边 :R
{
//RR
rrRotation(*T, T);
}
else//:L
{
//RL
rlTotation(T);
}
}
}
(*T)->height = GetMax(GetHeight((*T)->left_child), GetHeight((*T)->right_child)) + 1;
}
main
int main()
{
TreeNode* T = NULL;
int nums1[5] = { 1,2,3,4,5 };
int nums2[5] = { 5,4,3,2,1 };
int nums3[5] = { 8,7,9,5,6 };
int nums4[5] = { 1,8,6,7,10 };
for (int i = 0; i < 5; i++)
{ //构建树
AVLInsert(&T, nums4[i]);
}
PreOrder(T);
cout << endl;
return 0;
}
