- 作者:Cukor Zhong
什么是平衡二叉树
平衡二叉树是具有平衡
属性的有序二叉树
,所谓的平衡即当前树的左右子树高度差的绝对值不超过1。因为平衡二叉树
是由苏联数学家Adelson-Velskii
和Landis
提出,所以又称为AVL
树。
平衡二叉树的基本特点
- 是特殊的有序二叉树
- 左右子树高度差的绝对值不超过1
- 左右子树仍然是平衡二叉树
为什么会出现平衡二叉树
在学习平衡二叉树之前必定已经学过有序二叉树,有序二叉树的结构特点就是将数据有序的排好,查找起来快,但是有序二叉树有一个缺点,就是当节点呈现的状态是一边倒,那查找数据的时候就没有发挥出二叉树折半查找的优势了,这个时候是线性的查找(类似于链表的查找)。平衡二叉树就是解决有序二叉树一边倒的问题。如果有序二叉树是平衡的,那么查找数据就很快。时间复杂度为 O ( l o g n ) O(logn) O(logn)。这样就充分发挥了二叉树的优势。
二叉树四种不平衡的情况
当树的左右子树高度差的绝对值大于1的时候就需要进行旋转操作,将不平衡的树变成平衡的树。以下是会出现的四种不平衡的情况
。
- 左左不平衡
- 右右不平衡
- 左右不平衡
- 右左不平衡
左左不平衡旋转成平衡状态:
右右不平衡旋转成平衡状态:
左右不平衡旋转成平衡状态:
右左不平衡旋转成平衡状态:
上面是图解这四种不平衡状态旋转成平衡状态的情况。
C语言实现平衡二叉树
平衡二叉树的结构体描述:
#define Ty int //以整型数据为例
typedef struct Node
{
Ty data; //数据
int height; //高度
struct Node* LChild; //左子树
struct Node* RChild; //右子树
}Node,AVLTree;
初始化函数:
AVLTree* creatAVLTree(Ty data)
{
AVLTree* tree = (AVLTree*)malloc(sizeof(AVLTree));
assert(tree);
tree->data = data;
tree->height = 0;
tree->LChild = NULL;
tree->RChild = NULL;
return tree;
}
辅助宏函数:
//辅助函数
#define HEIGHT(x) ((x==NULL)?(-1):(x->height))
#define MAX(a,b) ((a>b)?(a):(b))
//获取树的新高度
#define GET_NEW_HEIGHT(x) (MAX(HEIGHT(x->LChild),HEIGHT(x->RChild)) + 1)
使用宏函数的好处是运行过程中不需要进行函数压栈的操作,效率快一点。
前序遍历平衡二叉树:
//前序打印
void show_pre(AVLTree* root)
{
if(root==NULL)
return;
printf("data:%d\theight:%d\n",root->data,root->height);
show_pre(root->LChild);
show_pre(root->RChild);
}
使用前序遍历能更好地看出节点的高度,更方便还原平衡二叉树。
四种不平衡状态旋转的算法实现:
算法核心思想:找到新根的位置,然后进行对应的调整,最后返回新根的地址,这样就实现了旋转的操作,因为旋转后节点的高度改变了,所以在返回之前先调整一下节点的高度。
例如:左左不平衡进行旋转操作
因为是左左不平衡,所以新根的位置是当前根的左子树,那就使用一个指针(newRoot
)去接收当前根的左子树,然后使劲将当前根拉下来,让新根代替当前根的位置,那就必须将当前根的LChild
指向newRoot
的右