查找篇-平衡二叉树(AVL)

219 阅读3分钟

平衡查找二叉树适合静态查找多于动态操作的场景。由于平衡二叉树的维护成本较高,工程中一般不用平衡二叉树,而是用红黑树代替。

平衡二叉树的优缺点

优点

平衡二叉树的平衡因子为-1,0或1,相比二叉查找树,平衡二叉树的查找成功的平均时间复杂度更加稳定。

缺点

平衡查找二叉树在不理想情况下,经常需要维护平衡因子,维护平衡因子可能需要较长的响应时间,对于响应时间敏感的应用来说是不能满足需求的。

代码实现

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef struct AVLNode {
    int data;
    int bf;
    struct AVLNode* lchild;
    struct AVLNode* rchild;
}AVLNode, * AVL;

//左旋
void L_Rotate(AVL* T) {
    if (*T == NULL) return;
    AVL rc = (*T)->rchild;
    (*T)->rchild = rc->lchild; //将*T的右孩子的左孩子作为*T的右孩子
    rc->lchild = *T; //将*T作为*T的右孩子的左孩子
    *T = rc;//用*T的左孩子取代*T
}

//右旋
void R_Rotate(AVL* T) {
    if (*T == NULL) return;
    AVL lc = (*T)->lchild;
    (*T)->lchild = lc->rchild; //将*T的左孩子的右孩子作为*T的左孩子
    lc->rchild = *T; //将*T作为*T左孩子的右孩子
    *T = lc;//用*T的you孩子取代*T
}

// 搜索结点
AVL search(AVL T, int data) {
    if (T == NULL) {
        return NULL;
    }
    if (T->data = data) {
        return T;
    }
    else if (data < T->data) {
        return search(T->lchild, data);
    }
    else {
        return search(T->rchild, data);
    }
}
//左平衡处理
void LeftBalance(AVL* T, bool* taller) {
    if (*T == NULL) return;
    AVL lc = (*T)->lchild;
    if ((*T)->bf == 1) { //LL型,进行一次右旋
        (*T)->bf = lc->bf = 0;
        R_Rotate(T);
    }
    else if ((*T)->bf == -1) {//LR型
       //更新bf
        AVL rc = (*T)->rchild;
        switch (rc->bf) {
        case -1:
            (*T)->bf = 0;
            lc->bf = 1;
        case 0:
            lc->bf = (*T)->bf = 0;
            break;
        case 1:
            (*T)->bf = -1;
            lc->bf = 0;
            break;
        }
        rc->bf = 0; //*T的左孩子的右子树的根将替换*T,且bf为0
        //先左旋
        L_Rotate(&(*T)->lchild);
        //再右旋
        R_Rotate(T);
    }
}
//右平衡处理
void RightBalance(AVL* T, bool* taller) {
    AVL rc = (*T)->rchild;
    if (rc->bf == -1) { // RR型
        (*T)->bf = rc->bf = 0;
        L_Rotate(T);
    }
    else if (rc->bf == 1) { //RL型
        AVL lc = rc->lchild;
        switch (lc->bf) {
        case -1:
            rc->bf = 0;
            (*T)->bf = 1;
            break;
        case 0:
            rc->bf = (*T)->bf = 0;
            break;
        case 1:
            rc->bf = -1;
            (*T)->bf = 0;
            break;
        }
        lc->bf = 0; //*T的右孩子的左子树的根将替换*T,且bf为0
        R_Rotate(&(*T)->rchild); //先右旋
        L_Rotate(T);//再左旋
    }
}
//插入结点
void insert(AVL* T, int data, bool* taller) {
    if (*T == NULL) { //插入空树
        AVL node = (AVL)malloc(sizeof(AVLNode));
        if (node == NULL) exit(0);
        node->data = data;
        node->bf = 0;
        node->lchild = node->rchild = NULL;
        *T = node;
        *taller = true; //树长高可能会导致不平衡
    }
    else if (data < (*T)->data) { //向左子树中插入
        insert(&(*T)->lchild, data, taller);
        if (*taller) {
            switch ((*T)->bf) {
            case -1:
                (*T)->bf = 0;
                *taller = false;
                break;
            case 0:
                (*T)->bf = 1;
                *taller = true;
                break;
            case 1:
                LeftBalance(T, taller);
                *taller = false;
                break;
            }
        }
    }
    else if (data > (*T)->data) { //向右子树中插入
        insert(&(*T)->rchild, data, taller);
        if (*taller) {
            switch ((*T)->bf) {
            case -1:
                RightBalance(T, taller);
                *taller = false;
                break;
            case 0:
                (*T)->bf = -1;
                *taller = true;
                break;
            case 1:
                (*T)->bf = 0;
                *taller = false;
                break;
            }
        }
    }
    else if (data == (*T)->data) {
        *taller = false;
        return;
    }
}

// 中序遍历
void inOrder(AVL root) {
    if (root == NULL) return;
    inOrder(root->lchild);
    printf("%d\n", root->data);
    inOrder(root->rchild);
}

//测试
int main() {
    int a[] = { 3,5,1,6,7,4,9 };
    int n = sizeof(a) / sizeof(int);
    AVL root = NULL;
    bool taller = false;
    for (int i = 0; i < n; i++) {
        insert(&root, a[i], &taller);
    }
    inOrder(root);
    return 0;
}