AVL Tree

113 阅读4分钟

概念:左右子树的高度差不能超过 1 的 Binary Search Tree, 即 AVL Tree。

1. 基本概念

  • AVL Tree 是自平衡的 Binary Search Tree
  • 树的节点都包含一个 balance factor,值为:-1、0、1;
  • balance factor 是左右子树的高度差;

1.1 树的节点的定义

struct avl_node {
    int key;
    int height;
    struct avl_node *lchild, *rchild;
};

2. AVL Tree 操作

2.1 Left Rotate

image.png

  • 操作步骤

    • 如果 y 有左子树,则将 x 的右子树指向 y 的左子树;
    • 如果 x 的父节点 p 为 NULL,则 y 变成根节点;
    • 否则 x 是父节点 p 的左子树,则将 y 变成 p 的左子树;
    • 否则将 y 变成 p 的右子树;
    • 然后将 x 变成 y 左子树;
  • 代码实现

struct avl_node *AVL_LeftRotate(struct avl_node *x)
{
    struct avl_node *y = x->rchild;
    struct avl_node *t = y->lchild;
    y->lchild = x;
    x->rchild = t;

    x->height = MAX(NodeHeight(x->lchild), NodeHeight(x->rchild)) + 1;
    y->height = MAX(NodeHeight(y->lchild), NodeHeight(y->rchild)) + 1;
    return y;
}

2.1 Right Rotate

image.png

  • 操作步骤

    • 如果 x 有右子树,则将 y 的左子树指向 x 的右子树;
    • 如果 y 的父节点 p 为 NULL,则 x 变成根节点;
    • 否则 y 是父节点 p 的右子树,则将 x 变成 p 的右子树;
    • 否则将 x 变成 p 的左子树;
    • 然后将 y 变成 x 的右子树;
  • 代码实现

struct avl_node *AVL_RightRotate(struct avl_node *y)
{
    struct avl_node *x = y->lchild;
    struct avl_node *t = x->rchild;
    x->rchild = y;
    y->lchild = t;

    y->height = MAX(NodeHeight(y->lchild), NodeHeight(y->rchild)) + 1;
    x->height = MAX(NodeHeight(x->lchild), NodeHeight(x->rchild)) + 1;

    return x;
}

2.2 AVL_Insert 插入

  • 操作步骤

    • 先将 key 插入到 tree 中
    • 更新树中各个节点的 height (balance factor)
    • 进行自平衡操作:左旋、右旋、左右旋、右左旋
      • 如果 balanceFactor > 1, 表示左子树的高度大于右子树的高度。
        • 如果 key < leftChildKey,则进行右旋;否则进行 left-right rotate
      • 如果 balanceFactor < -1, 表示右子树的高度大于左子树的高度。
        • 如果 key > rightChildKey,则进行左旋;否则进行 right-left rotate
  • 代码实现

struct avl_node *AVL_Insert(struct avl_node *root, int key)
{
    if (root == NULL) /* empty tree */
        return AVL_NewNode(key);

    if (key < root->key)
        root->lchild = AVL_Insert(root->lchild, key);
    else if (key > root->key)
        root->rchild = AVL_Insert(root->rchild, key);
    else
        return root;

    root->height = 1 + MAX(NodeHeight(root->lchild), NodeHeight(root->rchild));
    int balance = getBalance(root);
    if (balance > 1 && key < root->lchild->key)
        return AVL_RightRotate(root);

    if (balance > 1 && key > root->lchild->key) {
        root->left = AVL_LeftRotate(root->lchild);
        return AVL_RightRotate(root);
    }

    if (balance < -1 && key > root->rchild->key)
        return AVL_LeftRotate(root);

    if (balance < -1 && key < root->rchild->key) {
        root->right = AVL_RightRotate(root->rchild);
        return AVL_LeftRotate(root);
    }
    return root;
}

2.3 AVL_Delete 删除

image.png

  • 操作步骤
    • 通过递归找到要删除的节点;
    • 然后有以下三种情况:
      • nodeToBeDeleted 是叶子节点,直接删除即可;
      • nodeToBeDeleted 有一个子节点,用子节点的值替换掉 nodeToBeDeleted 的值,然后移除子节点;
      • nodeToBeDeleted 有两个子节点,找到其右子树的最小值的节点 w,然后用 w 的值替换掉 nodeToBeDeleted 的值,最后移除掉 w
    • 更新所有节点的 balanceFactor
    • 在利用旋转,保持树的平衡性(如果有任何一个节点的 balanceFactor 不等于 -1、0 或 1:
      • 如果当前节点 balanceFactor > 1
        • 如果当前节点的左子树的 balanceFactor >= 0,对当前节点做 right rotation
        • 否则对当前节点做 left-right-rotation
      • 如果当前节点 balanceFactor < -1
        • 如果当前节点的右子树的 balanceFactor <= 0,对当前节点做 left rotation;
        • 否则对当前节点做 right-left-rotation
  • 代码实现
struct avl_node *AVL_Delete(struct avl_node *root, int key)
{
    if (root == NULL)
        return root;

    if (key < root->key)
        root->lchild = AVL_Delete(root->lchild, key);
    else if (key > root->key)
        root->rchild = AVL_Delete(root->rchild, key);
    else {
        /* 此时,root 就是要删除的节点 */
        if ((root->lchild == NULL) || (root->rchild == NULL)) {
            struct avl_node *temp = root->lchild ? root->lchild : root->rchild;
            if (temp == NULL) {
                temp = root;
                root = NULL;
            } else
                *root = *temp;
            free(temp);
        } else {
            struct avl_node *temp = MinValueNode(root->rchild);
            root->key = temp->key;
            root->rchild = AVL_Delete(root->rchild, temp->key);
        }
    }

    /* empty tree */
    if (root == NULL)
        return root;

    /* Update the balance factor of each node and balance tree*/
    root->height = 1 + MAX(NodeHeight(root->lchild), NodeHeight(root->rchild));
    int balance = getBalance(root);
    if (balance > 1 && getBalance(root->lchild) >= 0)
        return AVL_RightRotate(root);
    if (balance > 1 && getBalance(root->lchild) < 0) {
        root->lchild = AVL_LeftRotate(root->lchild);
        return AVL_RightRotate(root);
    }
    if (balance < -1 && getBalance(root->rchild) <= 0)
        return AVL_LeftRotate(root);
    if (balance < -1 && getBalance(root->rchild) > 0) {
        root->rchild = AVL_RightRotate(root->rchild);
        return AVL_LeftRotate(root);
    }
    return root;
}

3. 完整代码

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

struct avl_node {
    int key;
    int height;
    struct avl_node *lchild, *rchild;
};

int max(int a, int b) {
  return (a > b) ? a : b;
}

int NodeHeight(const struct avl_node *node)
{
    if (node == NULL)
        return 0;
    return node->height;
}

struct avl_node *AVL_NewNode(int key)
{
    struct avl_node *temp = (struct avl_node *)malloc(sizeof(struct avl_node));
    if (temp == NULL) {
        perror("avl new node failed");
        exit(-1);
    }

    temp->key = key;
    temp->lchild = NULL;
    temp->rchild = NULL;
    temp->height = 1;
    return temp;
}

struct avl_node *AVL_RightRotate(struct avl_node *y)
{
    struct avl_node *x = y->lchild;
    struct avl_node *t = x->rchild;
    x->rchild = y;
    y->lchild = t;

    y->height = max(NodeHeight(y->lchild), NodeHeight(y->rchild)) + 1;
    x->height = max(NodeHeight(x->lchild), NodeHeight(x->rchild)) + 1;

    return x;
}

struct avl_node *AVL_LeftRotate(struct avl_node *x)
{
    struct avl_node *y = x->rchild;
    struct avl_node *t = y->lchild;
    y->lchild = x;
    x->rchild = t;

    x->height = max(NodeHeight(x->lchild), NodeHeight(x->rchild)) + 1;
    y->height = max(NodeHeight(y->lchild), NodeHeight(y->rchild)) + 1;
    return y;
}

int getBalance(struct avl_node *node)
{
    if (node == NULL)
        return 0;
    return NodeHeight(node->lchild) - NodeHeight(node->rchild);
}

struct avl_node *MinValueNode(struct avl_node *node)
{
    struct avl_node *p = node;
    while (p != NULL && p->lchild != NULL)
        p = p->lchild;
    return p;
}

struct avl_node *AVL_Insert(struct avl_node *root, int key)
{
    if (root == NULL) /* empty tree */
        return AVL_NewNode(key);

    if (key < root->key)
        root->lchild = AVL_Insert(root->lchild, key);
    else if (key > root->key)
        root->rchild = AVL_Insert(root->rchild, key);
    else
        return root;

    root->height = 1 + max(NodeHeight(root->lchild), NodeHeight(root->rchild));
    int balance = getBalance(root);
    if (balance > 1 && key < root->lchild->key)
        return AVL_RightRotate(root);

    if (balance > 1 && key > root->lchild->key) {
        root->lchild = AVL_LeftRotate(root->lchild);
        return AVL_RightRotate(root);
    }

    if (balance < -1 && key > root->rchild->key)
        return AVL_LeftRotate(root);

    if (balance < -1 && key < root->rchild->key) {
        root->rchild = AVL_RightRotate(root->rchild);
        return AVL_LeftRotate(root);
    }
    return root;
}

struct avl_node *AVL_Delete(struct avl_node *root, int key)
{
    if (root == NULL)
        return root;

    if (key < root->key)
        root->lchild = AVL_Delete(root->lchild, key);
    else if (key > root->key)
        root->rchild = AVL_Delete(root->rchild, key);
    else {
        /* 此时,root 就是要删除的节点 */
        if ((root->lchild == NULL) || (root->rchild == NULL)) {
            struct avl_node *temp = root->lchild ? root->lchild : root->rchild;
            if (temp == NULL) {
                temp = root;
                root = NULL;
            } else
                *root = *temp;
            free(temp);
        } else {
            struct avl_node *temp = MinValueNode(root->rchild);
            root->key = temp->key;
            root->rchild = AVL_Delete(root->rchild, temp->key);
        }
    }

    /* empty tree */
    if (root == NULL)
        return root;

    /* Update the balance factor of each node and balance tree*/
    root->height = 1 + max(NodeHeight(root->lchild), NodeHeight(root->rchild));
    int balance = getBalance(root);
    if (balance > 1 && getBalance(root->lchild) >= 0)
        return AVL_RightRotate(root);
    if (balance > 1 && getBalance(root->lchild) < 0) {
        root->lchild = AVL_LeftRotate(root->lchild);
        return AVL_RightRotate(root);
    }
    if (balance < -1 && getBalance(root->rchild) <= 0)
        return AVL_LeftRotate(root);
    if (balance < -1 && getBalance(root->rchild) > 0) {
        root->rchild = AVL_RightRotate(root->rchild);
        return AVL_LeftRotate(root);
    }
    return root;
}

void printPreOrder(struct avl_node *root)
{
    if (root != NULL) {
        printf("%d ", root->key);
        printPreOrder(root->lchild);
        printPreOrder(root->rchild);
    }
}

int main()
{
    struct avl_node *root = NULL;

    root = AVL_Insert(root, 2);
    root = AVL_Insert(root, 1);
    root = AVL_Insert(root, 7);
    root = AVL_Insert(root, 4);
    root = AVL_Insert(root, 5);
    root = AVL_Insert(root, 3);
    root = AVL_Insert(root, 8);

    printPreOrder(root);

    root = AVL_Delete(root, 3);

    printf("\nAfter deletion: ");
    printPreOrder(root);
    printf("\n");
    return 0;
}