http://dongxicheng.org/structure/avl/ 再次之后给出一份AVL的C++实现代码
1. 概述
AVL树是最早提出的自平衡二叉树,在AVL树中任何节点的两个子树的高度最大差别为一,所以它也被称为高度平衡树。AVL树得名于它的发明者G.M. Adelson-Velsky和E.M. Landis。AVL树种查找、插入和删除在平均和最坏情况下都是O(log n),增加和删除可能需要通过一次或多次树旋转来重新平衡这个树。本文介绍了AVL树的设计思想和基本操作。
2. 基本术语
有四种种情况可能导致二叉查找树不平衡,分别为:
(1)LL:插入一个新节点到根节点的左子树(Left)的左子树(Left),导致根节点的平衡因子由1变为2
(2)RR:插入一个新节点到根节点的右子树(Right)的右子树(Right),导致根节点的平衡因子由-1变为-2
(3)LR:插入一个新节点到根节点的左子树(Left)的右子树(Right),导致根节点的平衡因子由1变为2
(4)RL:插入一个新节点到根节点的右子树(Right)的左子树(Left),导致根节点的平衡因子由-1变为-2
针对四种种情况可能导致的不平衡,可以通过旋转使之变平衡。有两种基本的旋转:
(1)左旋转:将根节点旋转到(根节点的)右孩子的左孩子位置
(2)右旋转:将根节点旋转到(根节点的)左孩子的右孩子位置
3. AVL树的旋转操作
AVL树的基本操作是旋转,有四种旋转方式,分别为:左旋转,右旋转,左右旋转(先左后右),右左旋转(先右后左),实际上,这四种旋转操作两两对称,因而也可以说成两类旋转操作。
基本的数据结构:
typedef struct Node* Tree;
typedef struct Node* Node_t;
typedef Type int;
struct Node{
Node_t left;
Node_t right;
int height;
Type data;
};
int Height(Node_t node) {
return node->height;
}
3.1 LL
LL情况需要右旋解决,如下图所示:
代码为:
Node_t RightRotate(Node_t a) {
b = a->left;
a->left = b->right;
b->right = a;
a->height = Max(Height(a->left), Height(a->right));
b->height = Max(Height(b->left), Height(b->right));
return b;
}
3.2 RR
RR情况需要左旋解决,如下图所示:
代码为:
Node_t LeftRotate(Node_t a) {
b = a->right;
a->right = b->left;
b->left = a;
a->height = Max(Height(a->left), Height(a->right));
b->height = Max(Height(b->left), Height(b->right));
return b;
}
3.3 LR
LR情况需要左右(先B左旋转,后A右旋转)旋解决,如下图所示:
代码为:
Node_t LeftRightRotate(Node_t a) {
a->left = LeftRotate(a->left);
return RightRotate(a);
}
3.4 RL
RL情况需要右左旋解决(先B右旋转,后A左旋转),如下图所示:
代码为:
Node_t RightLeftRotate(Node_t a) {
a->right = RightRotate(a->right);
return LeftRotate(a);
}
4. AVL数的插入和删除操作
Node_t Insert(Type x, Tree t) {
if(t == NULL) {
t = NewNode(x);
} else if(x < t->data) {
t->left = Insert(t->left);
if(Height(t->left) - Height(t->right) == 2) {
if(x < t->left->data) {
t = RightRotate(t);
} else {
t = LeftRightRotate(t);
}
}
} else {
t->right = Insert(t->right);
if(Height(t->right) - Height(t->left) == 2) {
if(x > t->right->data) {
t = LeftRotate(t);
} else {
t = RightLeftRotate(t);
}
}
}
t->height = Max(Height(t->left), Height(t->right)) + 1;
return t;
}
(2) 删除操作:首先定位要删除的节点,然后用该节点的右孩子的最左孩子替换该节点,并重新调整以该节点为根的子树为AVL树,具体调整方法跟插入数据类似,代码如下:
Node_t Delete(Type x, Tree t) {
if(t == NULL) return NULL;
if(t->data == x) {
if(t->right == NULL) {
Node_t temp = t;
t = t->left;
free(temp);
} else {
Node_t head = t->right;
while(head->left) {
head = head->left;
}
t->data = head->data; //just copy data
t->right = Delete(t->data, t->right);
t->height = Max(Height(t->left), Height(t->right)) + 1;
}
return t;
} else if(t->data < x) {
Delete(x, t->right);
if(t->right) Rotate(x, t->right);
} else {
Delete(x, t->left);
if(t->left) Rotate(x, t->left);
}
if(t) Rotate(x, t);
}
5. 总结
AVL树是最早的自平衡二叉树,相比于后来出现的平衡二叉树(红黑树,treap,splay树)而言,它现在应用较少,但研究AVL树对于了解后面出现的常用平衡二叉树具有重要意义。
6. 参考资料
(1) 数据结构(C语言版) 严蔚敏,吴伟民著
(2) http://zh.wikipedia.org/wiki/AVL%E6%A0%91
(3)http://www.cppblog.com/goodwin/archive/2011/08/08/152797.html
(4)http://www.asiteof.me/2010/06/avl/
———————————————————————————————-
更多关于数据结构和算法的介绍,请查看:数据结构与算法汇总
以上AVL的实现如下:#pragma once
/*
http://dongxicheng.org/structure/avl/
*/
#define ElementType int
#define Max(a,b) (a)>(b)?(a):(b)
struct AvlNode;
typedef struct AvlNode* Position;
typedef struct AvlNode* AvlTree;
//释放树的空间
void ClearTree(AvlTree t);
//计算节点的高度
int Height(Position p);
//插入节点
AvlTree Insert(ElementType x,AvlTree t);
AvlTree Delete(ElementType x,AvlTree& tree);
//先序遍历
void Preorder_TreePrint(AvlTree t);
//中序遍历
void Inorder_TreePrint(AvlTree t);
//后序遍历
void Postorder_TreePrint(AvlTree t);
//针对左子树做单旋转
static Position SingleRotateWithLeft(Position k2);//右旋转
//针对右子树做单旋转
static Position SingleRotateWithRight(Position k2);//左旋转
//针对左子树做双旋转
static Position DoubleRotateWithLeft(Position k2);//先左旋后右旋
//针对右子树做双旋转
static Position DoubleRotateWithRight(Position k2);//先右旋后左旋
//
AvlTree Rotate(AvlTree T);
AvlTree FindElement(AvlTree T,ElementType x);
struct AvlNode
{
ElementType Element;
AvlTree Left;
AvlTree Right;
int Height;
};
#include "stdafx.h"
#include "AVL.h"
#include <stdlib.h>
#include <stdio.h>
//清空树
void ClearTree(AvlTree t)
{
if(t!=NULL)
{
ClearTree(t->Left);
ClearTree(t->Right);
free(t);
}
}
//前序遍历
void Preorder_TreePrint(AvlTree t)
{
if(t)
{
printf("%d(%d)\n",t->Element,t->Height);
Preorder_TreePrint(t->Left);
Preorder_TreePrint(t->Right);
}
}
//中序遍历
void Inorder_TreePrint(AvlTree t)
{
if(t)
{
Inorder_TreePrint(t->Left);
printf("%d(%d)\n",t->Element,t->Height);
Inorder_TreePrint(t->Right);
}
}
AvlTree Rotate(AvlTree T)
{
if(Height(T->Left)-Height(T->Right)==2)
{
if(T->Left)
{
if(Height(T->Left->Left)>=Height(T->Left->Right))
{//执行一次右旋操作
T=SingleRotateWithLeft(T);
}
if(Height(T->Left->Left)<Height(T->Left->Right))
T=DoubleRotateWithLeft(T);
}
else
{
T=SingleRotateWithLeft(T);
}
}
if(Height(T->Right)-Height(T->Left)==2)
{
if(T->Right)
{
if(Height(T->Right->Right)>=Height(T->Right->Left))
{
T=SingleRotateWithRight(T);//此处应该左旋
}
if(Height(T->Right->Right)<Height(T->Right->Left))
T=DoubleRotateWithRight(T);//此处应该先右旋再左旋
}
else
T=SingleRotateWithRight(T);
}
return T;
}
//删除节点
AvlTree Delete(ElementType key,AvlTree& t)
{
if(t==NULL)
return NULL;
if(key==t->Element)
{
if(t->Right==NULL)
{
AvlTree temp=t;
t=t->Left;
free(temp);
}
else
{
AvlTree temp=t->Right;
while(temp->Left!=NULL)
temp=temp->Left;
t->Element=temp->Element;
t->Right=Delete(temp->Element,t->Right);
t->Height=Max(Height(t->Left),Height(t->Right));
}
return t;
}
else if(key<t->Element)
{
t->Left=Delete(key,t->Left);
}
else
{
t->Right=Delete(key,t->Right);
}
t->Height=Max(Height(t->Left),Height(t->Right));//计算t的高度
//从删除的路径上向上找到不平衡点,直到root结点。调用旋转的次数可能不止一次
if(t->Left!=NULL)//平衡t的左孩子
t->Left=Rotate(t->Left);
if(t->Right!=NULL) //平衡t的右边孩子
t->Right=Rotate(t->Right);
t=Rotate(t);//平衡t本身
return t;
}
//插入节点
AvlTree Insert(ElementType x,AvlTree t)
{
if(t==NULL)
{
t=(AvlTree)malloc(sizeof(struct AvlNode));
if(t==NULL)
printf("out of space\n");
else
{
t->Element=x;
t->Left=NULL;
t->Right=NULL;
t->Height=0;
}
}
else if(x<t->Element)//左子树
{
t->Left=Insert(x,t->Left);
if(Height(t->Left)-Height(t->Right)==2)
{
if(x<t->Left->Element)
{
t=SingleRotateWithLeft(t);//右旋转
}
else
t=DoubleRotateWithLeft(t);//双旋转
}
}
else if(x>t->Element)//右子树
{
t->Right=Insert(x,t->Right);
if(Height(t->Right)-Height(t->Left)==2)
{
if(x>t->Right->Element)
t=SingleRotateWithRight(t);
else
t=DoubleRotateWithRight(t);
}
}
t->Height=Max(Height(t->Left),Height(t->Right))+1;
return t;
}
int Height(Position p)
{
if(p==NULL)
return 0;
else
return Max(Height(p->Left),Height(p->Right))+1;
}
static Position SingleRotateWithLeft(Position k2)//左旋
{
Position k1;
k1=k2->Left;
k2->Left=k1->Right;
k1->Right=k2;
k2->Height=Max(Height(k2->Left),Height(k2->Right))+1;
k1->Height=Max(Height(k1->Left),Height(k1->Right))+1;
return k1;
}
static Position SingleRotateWithRight(Position k2)//右旋转
{
Position k1;
k1=k2->Right;
k2->Right=k1->Left;
k1->Left=k2;
k2->Height=Max(Height(k2->Left),Height(k2->Right))+1;
k1->Height=Max(Height(k1->Left),Height(k1->Right))+1;
return k1;
}
//针对左子树双旋转
static Position DoubleRotateWithLeft(Position k3)
{
k3->Left=SingleRotateWithLeft(k3->Left);
return SingleRotateWithLeft(k3);
}
//针对右子树做双旋转
static Position DoubleRotateWithRight(Position k3)
{
k3->Right=SingleRotateWithRight(k3->Right);
return SingleRotateWithRight(k3);
}
AvlTree FindElement(AvlTree T,ElementType x)
{
if(x==T->Element)
return T;
else if(x<T->Element)
{
FindElement(T->Left,x);
}
else
FindElement(T->Right,x);
return NULL;
}
int main(){
int i=0;
AvlTree at=NULL;
for(i=0;i<10;i++)
at=Insert(i,at);
cout<<"中序遍历"<<endl;
Inorder_TreePrint(at);
Delete(2,at);
cout<<endl;
Inorder_TreePrint(at);
AvlTree temp=FindElement(at,3);
cout<<temp->Height<<" "<<temp->Element<<" ";
ClearTree(at);
return 0;
}