數(shù)據(jù)結(jié)構(gòu)與算法-AVL樹

1. 基礎(chǔ)數(shù)據(jù)結(jié)構(gòu)

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

/// 平衡二叉樹
typedef struct BiTNode {
    int data; // 數(shù)據(jù)
    int bf; // 平衡因子
    struct BiTNode *lchild, *rchild; // 左右孩子指針
} BiTNode, *BiTree;

2. 左旋右旋

這里以右旋為例是牢,P斷開了左指針系宫,L斷開右指針乌庶;L空出來(lái)的右指針指向P,P空出來(lái)的左指針指向L_R

右旋
/// 左旋
void R_Rotate(BiTree *p) {
    BiTree L = (*p)->lchild; // L是p的左子樹
    (*p)->lchild = L->rchild; // L的右子樹作為p的左子樹
    L->rchild = *p; // 將p作為L(zhǎng)的右子樹
    *p = L; // 將L替換原有p的根結(jié)點(diǎn)位置
}

/// 右旋
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的根結(jié)點(diǎn)位置
}

3. 左失衡右失衡

/// 左失衡
void LeftBalance(BiTree *T) {
    BiTree Tl = (*T)->lchild;
    BiTree Lr;
    switch (Tl->bf) {
        case LH: // 新結(jié)點(diǎn)插入在T的左孩子的左子樹上
            (*T)->bf = Tl->bf = EH; // 調(diào)整后平衡
            R_Rotate(T); // 進(jìn)行右旋
            break;
        case RH: // 新結(jié)點(diǎn)插入在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); // 對(duì)T的左子樹作左旋平衡處理
            R_Rotate(T); // 對(duì)T作右旋平衡處理
            break;
    }
}

/// 右失衡
void RightBalance(BiTree *T) {
    BiTree Tr = (*T)->rchild;
    BiTree Rl;
    switch (Tr->bf) {
        case RH: // 新結(jié)點(diǎn)插入在T的右孩子的右子樹上
            (*T)->bf = Tr->bf = EH; // 調(diào)整后平衡
            L_Rotate(T); // 進(jìn)行左旋
            break;
        case LH: // 新結(jié)點(diǎn)插入在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); // 對(duì)T的右子樹作右旋平衡處理
            L_Rotate(T); // 對(duì)T作左旋平衡處理
            break;
    }
}

4. 插入結(jié)點(diǎn)

/// 插入結(jié)點(diǎn)
/// @param T AVL樹
/// @param data 被插入數(shù)據(jù)
/// @param taller 是否"長(zhǎng)高"
Status InsertAVL(BiTree *T, int data, Status *taller) {
    if (!*T) { // 空結(jié)點(diǎn)
        *T = (BiTree)malloc(sizeof(BiTNode));
        (*T)->data = data;
        (*T)->lchild = (*T)->rchild = NULL; // 新結(jié)點(diǎn)沒(méi)有左右子樹
        (*T)->bf = EH;
        *taller = TRUE; // 新結(jié)點(diǎn)默認(rèn)"長(zhǎng)高"
    } else {
        if (data == (*T)->data) { // 已存在和data有相同關(guān)鍵字的結(jié)點(diǎn)則不再插入
            *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:
                        // 原本左、右子樹等高拣度,現(xiàn)因左子樹增高而使樹增高
                        (*T)->bf = LH;
                        *taller = TRUE;
                        break;
                    case RH:
                        // 原本右子樹比左子樹高碎绎,現(xiàn)左右子樹等高
                        (*T)->bf = EH;
                        *taller = FALSE;
                        break;
                }
            }
        } else { // 大則在右子樹插入
            if (!InsertAVL(&(*T)->rchild, data, taller)) // 插入失敗
                return FALSE;
            // 插入成功
            if (*taller) {
                switch ((*T)->bf) {
                    case LH:
                        // 原本左子樹比右子樹高,現(xiàn)左右子樹等高
                        (*T)->bf = EH;
                        *taller = FALSE;
                        break;
                    case EH:
                        // 原本左抗果、右子樹等高筋帖,現(xiàn)因右子樹增高而使樹增高
                        (*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 最后一個(gè)被訪問(wèn)結(jié)點(diǎn)的指針引用
///
/// 若指針p指向查找路徑上訪問(wèn)的最后一個(gè)結(jié)點(diǎn)則返回FALSE
Status SearchBST(BiTree T, int key, BiTree f, BiTree *p) {
    if (!T) { // 空結(jié)點(diǎn)
        *p = f; // 查詢失敗,指回雙親結(jié)點(diǎn)
        return FALSE;
    } else if (key == T->data) { // 根節(jié)點(diǎn)查詢成功
        *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;
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市嗡综,隨后出現(xiàn)的幾起案子乙帮,更是在濱河造成了極大的恐慌,老刑警劉巖极景,帶你破解...
    沈念sama閱讀 219,039評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件察净,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡盼樟,警方通過(guò)查閱死者的電腦和手機(jī)氢卡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)恤批,“玉大人异吻,你說(shuō)我怎么就攤上這事∠才樱” “怎么了诀浪?”我有些...
    開封第一講書人閱讀 165,417評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)延都。 經(jīng)常有香客問(wèn)我雷猪,道長(zhǎng),這世上最難降的妖魔是什么晰房? 我笑而不...
    開封第一講書人閱讀 58,868評(píng)論 1 295
  • 正文 為了忘掉前任求摇,我火速辦了婚禮,結(jié)果婚禮上殊者,老公的妹妹穿的比我還像新娘与境。我一直安慰自己,他們只是感情好猖吴,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評(píng)論 6 392
  • 文/花漫 我一把揭開白布摔刁。 她就那樣靜靜地躺著,像睡著了一般海蔽。 火紅的嫁衣襯著肌膚如雪共屈。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,692評(píng)論 1 305
  • 那天党窜,我揣著相機(jī)與錄音拗引,去河邊找鬼。 笑死幌衣,一個(gè)胖子當(dāng)著我的面吹牛矾削,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 40,416評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼怔软,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼垦细!你這毒婦竟也來(lái)了择镇?” 一聲冷哼從身側(cè)響起挡逼,我...
    開封第一講書人閱讀 39,326評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎腻豌,沒(méi)想到半個(gè)月后家坎,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,782評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡吝梅,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評(píng)論 3 337
  • 正文 我和宋清朗相戀三年虱疏,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片苏携。...
    茶點(diǎn)故事閱讀 40,102評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡做瞪,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出右冻,到底是詐尸還是另有隱情装蓬,我是刑警寧澤,帶...
    沈念sama閱讀 35,790評(píng)論 5 346
  • 正文 年R本政府宣布纱扭,位于F島的核電站牍帚,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏乳蛾。R本人自食惡果不足惜暗赶,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望肃叶。 院中可真熱鬧蹂随,春花似錦、人聲如沸因惭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)筛欢。三九已至浸锨,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間版姑,已是汗流浹背柱搜。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留剥险,地道東北人聪蘸。 一個(gè)月前我還...
    沈念sama閱讀 48,332評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親健爬。 傳聞我的和親對(duì)象是個(gè)殘疾皇子控乾,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評(píng)論 2 355