数据结构与算法分析-AVL树深入探讨

数据结构与算法分析-AVL树深入探讨

数据结构与算法分析-AVL树深入探讨

1 数据结构之-AVL树深入探讨

之前学习数据结构与算法分析C语言描述的时候, 学到了AVL树, 陷入了重重的陷阱, 如今把一一踩过的陷阱都描述出来, 好让自己温故知新.

1.1 AVL树介绍

  • AVL(Adelson-Velskii和Landis)树是带有平衡条件的二叉查找树.这个平衡条件必须要容易保持.而且它须保证树的深度是 \(O(\log{N})\).
  • 一棵AVL树是其任意节点的左子树和右子树的高度绝对值最多差1的二叉查找树.
  • 下图是AVL树和非AVL树

pic1.png

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种情形的图

pic2.png pic3.png

1.4 解决不平衡情形-旋转

  • 中, 只有单旋和双旋这两个概念,我觉得这个概念不太好理解,所以在下面再稍作解释.
  • 我首先说明, 下面的右旋转是指顺时针旋转,左旋转是指逆时针旋转.

1.4.1 LL情形

  • 对于 LL 情形,需要一次 右旋转 即可将树平衡, 新平衡节点为 k1

pic4.png

  • 实现代码如下
/* 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

pic5.png

  • 实现代码如下
/* 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 情形,需要 k2k1 一次 左旋转, 然后对 k2k3 进行一次 右旋转 新平衡节点为 k2

pic6.png

  • 实现代码如下
/* 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 情形,需要 k2k1 一次 右旋转, 然后对 k2k3 进行一次 左旋转 新平衡节点为 k2

pic7.png

  • 实现代码如下
/* 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;
    }
}

Date: 2018-11-19 22:15

Author: devinkin

Created: 2018-11-20 二 13:01

Validate

posted @ 2018-11-19 22:16  EmacsDevinkin  阅读(291)  评论(0编辑  收藏  举报