数据结构与算法分析-AVL树深入探讨
Table of Contents
1 数据结构之-AVL树深入探讨
之前学习数据结构与算法分析C语言描述的时候, 学到了AVL树, 陷入了重重的陷阱, 如今把一一踩过的陷阱都描述出来, 好让自己温故知新.
1.1 AVL树介绍
- AVL(Adelson-Velskii和Landis)树是带有平衡条件的二叉查找树.这个平衡条件必须要容易保持.而且它须保证树的深度是 \(O(\log{N})\).
- 一棵AVL树是其任意节点的左子树和右子树的高度绝对值最多差1的二叉查找树.
- 下图是AVL树和非AVL树
1.2 AVL树数据结构
- 由于AVL树记录的信息比二叉树多了一项高度,所以需要在二叉树数据结构中添加高度成员.
struct AvlNode { ElementType Element; AvlTree Left; AvlTree Right; int Height; };
1.3 AVL树的四种不平衡情形
- AVL树的任意节点
a
的两棵子树(左儿子和右儿子)的高度差2就会出现不平衡状态. - 不平衡情形分为四种,
a
为不平衡节点.- 对
a
的左儿子(L)的左子树(L)进行一次插入.LL情形
- 对
a
的左儿子(L)的右子树(R)进行一次插入.LR情形
- 对
a
的右儿子(R)的左子树(L)进行一次插入.RL情形
- 对
a
的右儿子(R)的右边子树(R)进行一次插入.RR情形
- 对
- 以下是4种情形的图
1.4 解决不平衡情形-旋转
1.4.1 LL情形
- 对于
LL
情形,需要一次右旋转
即可将树平衡, 新平衡节点为k1
- 实现代码如下
/* LL情形旋转,右旋转 */ static Position SingleRotateWithLeft(Position K2) { Position K1; K1 = K2->Left; /* K2左子树变为K1右子树, K2右子树不变 */ K2->Left = K1->Right; /* K1右子树变为K2, K1左子树不变 */ K1->Right = K2; /* K1为新的根节点,所以先算K2的高度 */ K2->Height = Max(Height(K2->Left), Height(K2->Right)) + 1; K1->Height = Max(Height(K1->Left), K2->Height) + 1; /* New Root */ return K1; }
1.4.2 RR情形
- 对于
RR
情形,需要一次左旋转
即可将树平衡, 新平衡节点为k1
- 实现代码如下
/* RR情形旋转,左旋转 */ static Position SingleRotateWithRight(Position K2) { Position K1; K1 = K2->Right; /* K2右子树变为K1左子树, K2左子树不变 */ K2->Right = K1->Left; /* K1左子树变为K2, K1右子树不变 */ K1->Left = K2; /* K1为新的根节点,所以先算K2的高度 */ K2->Height = Max(Height(K2->Left), Height(K2->Right)); K1->Height = Max(K2->Height, Height(K1->Right)); /* New Root */ return K1; }
1.4.3 LR情形
- 对于
LR
情形,需要k2
和k1
一次左旋转
, 然后对k2
和k3
进行一次右旋转
新平衡节点为k2
- 实现代码如下
/* LR情形旋转,先右旋转后左旋转 */ static Position DoubleRotateWithLR(Position K3) { /* Rotate between K1 and K2 */ /* 先右旋,此时是右儿子 */ K3->Right = SingleRotateWithLeft(K3->Right); /* Rotate between K3 and K2 */ /* 后左旋 */ return SingleRotateWithRight(K3); }
1.4.4 RL情形
- 对于
RL
情形,需要k2
和k1
一次右旋转
, 然后对k2
和k3
进行一次左旋转
新平衡节点为k2
- 实现代码如下
/* RL情形旋转,先左旋转后右旋转 */ static Position DoubleRotateWithRL(Position K3) { /* Rotate between K1 and K2 */ /* 先左旋,此时是左儿子 */ K3->Left = SingleRotateWithRight(K3->Left); /* Rotate between K3 and K2 */ /* 后右旋 */ return SingleRotateWithLeft(K3); }
1.5 AVL树的实现代码
- avltree.h
#ifndef _AVLTREE_H #define _AVLTREE_H struct AvlNode; typedef struct AvlNode *Position; typedef struct AvlNode *AvlTree; typedef int ElementType; AvlTree MakeEmpty(AvlTree T); Position Find(ElementType X, AvlTree T); Position FindMin(AvlTree T); Position FindMax(AvlTree T); AvlTree Insert(ElementType X, AvlTree T); AvlTree Delete(ElementType X, AvlTree T); ElementType Retrieve(Position P); struct AvlNode { ElementType Element; AvlTree Left; AvlTree Right; int Height; }; #endif
- avltree.c
#include "avltree.h" #include "utils.h" #include <stdio.h> #include <stdlib.h> static int Height(Position P) { if (P == NULL) { return -1; } else { return P->Height; } } AvlTree MakeEmpty(AvlTree T) { if (T != NULL) { MakeEmpty(T->Left); MakeEmpty(T->Right); free(T); } return NULL; } Position Find(ElementType X, AvlTree T) { if (T != NULL) { if (X < T->Element) { return Find(X, T->Left); } else if (X > T->Element) { return Find(X, T->Right); } else { return T; } } else { return NULL; } } Position FindMin(AvlTree T) { if (T == NULL) { return NULL; } else if (T->Left == NULL) { return T; } else { return FindMin(T->Left); } } Position FindMax(AvlTree T) { if (T == NULL) { return NULL; } else if (T->Right == NULL) { return T; } else { return FindMax(T->Right); } } /* LL情形旋转,右旋转 */ static Position SingleRotateWithLeft(Position K2) { Position K1; K1 = K2->Left; /* K2左子树变为K1右子树, K2右子树不变 */ K2->Left = K1->Right; /* K1右子树变为K2, K1左子树不变 */ K1->Right = K2; /* K1为新的根节点,所以先算K2的高度 */ K2->Height = Max(Height(K2->Left), Height(K2->Right)) + 1; K1->Height = Max(Height(K1->Left), K2->Height) + 1; /* New Root */ return K1; } /* RR情形旋转,左旋转 */ static Position SingleRotateWithRight(Position K2) { Position K1; K1 = K2->Right; /* K2右子树变为K1左子树, K2左子树不变 */ K2->Right = K1->Left; /* K1左子树变为K2, K1右子树不变 */ K1->Left = K2; /* K1为新的根节点,所以先算K2的高度 */ K2->Height = Max(Height(K2->Left), Height(K2->Right)); K1->Height = Max(K2->Height, Height(K1->Right)); /* New Root */ return K1; } /* RL情形旋转,先左旋转后右旋转 */ static Position DoubleRotateWithRL(Position K3) { /* Rotate between K1 and K2 */ /* 先左旋,此时是左儿子 */ K3->Left = SingleRotateWithRight(K3->Left); /* Rotate between K3 and K2 */ /* 后右旋 */ return SingleRotateWithLeft(K3); } /* LR情形旋转,先右旋转后左旋转 */ static Position DoubleRotateWithLR(Position K3) { /* Rotate between K1 and K2 */ /* 先右旋,此时是右儿子 */ K3->Right = SingleRotateWithLeft(K3->Right); /* Rotate between K3 and K2 */ /* 后左旋 */ return SingleRotateWithRight(K3); } AvlTree Insert(ElementType X, AvlTree T) { if (T == NULL) { /* Create and return a one-node tree */ T = malloc(sizeof(struct AvlNode)); if (T == NULL) { printf("Out of memory!!!"); exit(-1); } else { T->Element = X; T->Height = 0; T->Left = T->Right = NULL; } } else if (X < T->Element) { T->Left = Insert(X, T->Left); if (Height(T->Left) - Height(T->Right) == 2) { if (X < T->Element) { /* LL situation, right rotation */ T = SingleRotateWithLeft(T); } else { /* LR situation, right rotation and then left rotation */ T = DoubleRotateWithLR(T); } } } else if (X > T->Element) { T->Right = Insert(X, T->Right); if (Height(T->Right) - Height(T->Left) == 2) { if (X > T->Element) { /* RR situation, left rotation */ T = SingleRotateWithRight(T); } else { /* RL situation, left rotation and then right rotation */ T = DoubleRotateWithRL(T); } } } /* Else X is in the tree already; we'll do nothing */ T->Height = Max(Height(T->Left), Height(T->Right)) + 1; return T; } AvlTree Delete(ElementType X, AvlTree T) { Position TmpCell; if (T == NULL) { printf("Element not found"); exit(-1); } else if (X < T->Element) { /* Go left */ T->Left = Delete(X, T->Left); } else if (X > T->Element) { /* Go right */ T->Right = Delete(X, T->Right); } else { /* Found element to be deleted */ if (T->Left && T->Right) { /* Two childrens */ /* Replace with smallest in right subtree */ TmpCell = FindMin(T->Right); T->Element = TmpCell->Element; T->Right = Delete(T->Element, T->Right); } else { /* One of zero childrens */ TmpCell = T; if (T->Left == NULL) { T = T->Right; } else if (T->Right == NULL) { T = T->Left; } else { free(TmpCell); } } } return T; } ElementType Retrieve(Position P) { if (P != NULL) { return P->Element; } else { return -1; } }