数据结构与算法-AVL树

1. 基础数据结构

#define LH +1 /*  左高 */
#define EH 0  /*  等高 */
#define RH -1 /*  右高 */

/// 平衡二叉树
typedef struct BiTNode {
    int data; // 数据
    int bf; // 平衡因子
    struct BiTNode *lchild, *rchild; // 左右孩子指针
} BiTNode, *BiTree;

2. 左旋右旋

这里以右旋为例,P断开了左指针,L断开右指针;L空出来的右指针指向P,P空出来的左指针指向L_R

右旋
/// 左旋
void R_Rotate(BiTree *p) {
    BiTree L = (*p)->lchild; // L是p的左子树
    (*p)->lchild = L->rchild; // L的右子树作为p的左子树
    L->rchild = *p; // 将p作为L的右子树
    *p = L; // 将L替换原有p的根结点位置
}

/// 右旋
void L_Rotate(BiTree *p) {
    BiTree R = (*p)->rchild; // R是p的右子树
    (*p)->rchild = R->lchild; // R的左子树作为R的右子树
    R->lchild = *p; // 将p作为R的左子树
    *p = R; // 将R替换原有p的根结点位置
}

3. 左失衡右失衡

/// 左失衡
void LeftBalance(BiTree *T) {
    BiTree Tl = (*T)->lchild;
    BiTree Lr;
    switch (Tl->bf) {
        case LH: // 新结点插入在T的左孩子的左子树上
            (*T)->bf = Tl->bf = EH; // 调整后平衡
            R_Rotate(T); // 进行右旋
            break;
        case RH: // 新结点插入在T的左孩子的右子树上
            Lr = Tl->rchild; // Lr指向T的左孩子的右子树
            // 修改T及其左孩子的平衡因子
            switch (Lr->bf) {
                case LH:
                    Tl->bf = RH;
                    (*T)->bf = EH;
                    break;
                 case EH:
                    Tl->bf = (*T)->bf = EH;
                    break;
                case RH:
                    Tl->bf = EH;
                    (*T)->bf = LH;
                    break;
            }
            Lr->bf = EH;
            L_Rotate(&(*T)->lchild); // 对T的左子树作左旋平衡处理
            R_Rotate(T); // 对T作右旋平衡处理
            break;
    }
}

/// 右失衡
void RightBalance(BiTree *T) {
    BiTree Tr = (*T)->rchild;
    BiTree Rl;
    switch (Tr->bf) {
        case RH: // 新结点插入在T的右孩子的右子树上
            (*T)->bf = Tr->bf = EH; // 调整后平衡
            L_Rotate(T); // 进行左旋
            break;
        case LH: // 新结点插入在T的右孩子的左子树上
            Rl = Tr->lchild; // Ll指向T的右孩子的左子树
            // 修改T及其左孩子的平衡因子
            switch (Rl->bf) {
                case LH:
                    Tr->bf = EH;
                    (*T)->bf = RH;
                    break;
                 case EH:
                    Tr->bf = (*T)->bf = EH;
                    break;
                case RH:
                    Tr->bf = LH;
                    (*T)->bf = EH;
                    break;
            }
            Rl->bf = EH;
            R_Rotate(&(*T)->rchild); // 对T的右子树作右旋平衡处理
            L_Rotate(T); // 对T作左旋平衡处理
            break;
    }
}

4. 插入结点

/// 插入结点
/// @param T AVL树
/// @param data 被插入数据
/// @param taller 是否"长高"
Status InsertAVL(BiTree *T, int data, Status *taller) {
    if (!*T) { // 空结点
        *T = (BiTree)malloc(sizeof(BiTNode));
        (*T)->data = data;
        (*T)->lchild = (*T)->rchild = NULL; // 新结点没有左右子树
        (*T)->bf = EH;
        *taller = TRUE; // 新结点默认"长高"
    } else {
        if (data == (*T)->data) { // 已存在和data有相同关键字的结点则不再插入
            *taller = FALSE;
            return FALSE;
        }
        if (data < (*T)->data) { // 小则在左子树插入
            if (!InsertAVL(&(*T)->lchild, data, taller)) // 插入失败
                return FALSE;
            // 插入成功
            if (*taller) {
                switch ((*T)->bf) {
                    case LH:
                        // 原本左子树比右子树高,需要作左平衡处理
                        LeftBalance(T);
                        *taller = FALSE;
                        break;
                    case EH:
                        // 原本左、右子树等高,现因左子树增高而使树增高
                        (*T)->bf = LH;
                        *taller = TRUE;
                        break;
                    case RH:
                        // 原本右子树比左子树高,现左右子树等高
                        (*T)->bf = EH;
                        *taller = FALSE;
                        break;
                }
            }
        } else { // 大则在右子树插入
            if (!InsertAVL(&(*T)->rchild, data, taller)) // 插入失败
                return FALSE;
            // 插入成功
            if (*taller) {
                switch ((*T)->bf) {
                    case LH:
                        // 原本左子树比右子树高,现左右子树等高
                        (*T)->bf = EH;
                        *taller = FALSE;
                        break;
                    case EH:
                        // 原本左、右子树等高,现因右子树增高而使树增高
                        (*T)->bf = RH;
                        *taller = TRUE;
                        break;
                    case RH:
                        // 原本右子树比左子树高,需要作右平衡处理
                        RightBalance(T);
                        *taller = FALSE;
                        break;
                }
            }
        }
    }
    return TRUE;
}

5. 查询

查询和二叉搜索树相同。

/// 递归查找二叉排序树T中,是否存在key
/// @param T AVL树
/// @param key 被查询值
/// @param f 指针f指向T的双亲,初始值为NULL
/// @param p 最后一个被访问结点的指针引用
///
/// 若指针p指向查找路径上访问的最后一个结点则返回FALSE
Status SearchBST(BiTree T, int key, BiTree f, BiTree *p) {
    if (!T) { // 空结点
        *p = f; // 查询失败,指回双亲结点
        return FALSE;
    } else if (key == T->data) { // 根节点查询成功
        *p = T;
        return TRUE;
    } else if (key < T->data) { // 查询值跟小,则在左子树中找
        return SearchBST(T->lchild, key, T, p);
    } else { // 查询值更大,则在右子树中找
        return SearchBST(T->rchild, key, T, p);
    }
    return TRUE;
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,569评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,499评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,271评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,087评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,474评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,670评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,911评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,636评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,397评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,607评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,093评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,418评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,074评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,092评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,865评论 0 196
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,726评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,627评论 2 270