C語言 AVL樹

AVL樹簡介

AVL樹的基本操作一般涉及運做同在不平衡的二叉查找樹所運做的同樣的算法。但是要進行預先或隨後做一次或多次所謂的”AVL 旋轉”。

AVL樹的模擬過程可以看鏈接:AVLtree

對於AVL樹的詳細簡介和實現過程可以參照鏈接:數據結構圖文解析之:AVL樹詳解及C++模板實現

我在這裏主要是選出重點:AVL旋轉

實現過程

首先我們需要知道什麼情況下需要AVL旋轉。
節點的左右子樹的高度差大於 1 的時候,二叉樹不平衡了,這個時候我們需要進行AVL操作。

主要有以下幾種情況:
這裏寫圖片描述

通過右旋,左旋,右旋左旋,左旋右旋使得二叉樹平衡。
那麼怎麼實現四種AVL旋轉?可以發現右旋和左旋的實現比較簡單,都是將中心節點變換爲根節點,而右旋左旋,左旋右旋則比較複雜。
實際上,我們可以這樣看,右旋左旋其實相當於進行了兩次旋轉,一次旋轉是右旋,它並不是將三個節點進行旋轉,而是將後兩個節點先進行一輪旋轉(可以想象爲兩個節點最後帶一個空節點),另外一個節點是對旋轉完成後進行了一次左旋。比如:
這裏寫圖片描述

所以對於右旋左旋,左旋右旋的實現就變得簡單很多:

BtreePtr rightLeftRotate(BtreePtr a) {
    a->right_child = rightRotate(a->right_child);
    a = leftRotate(a);
    return a;
}

BtreePtr leftRightRotate(BtreePtr a) {
    a->left_child = leftRotate(a->left_child);
    a = leftRotate(a);
    return a;
}

代碼實現

節點的結構體

typedef struct Bi{
    int val;
    int pos;

    int height;
    struct Bi *parent;
    struct Bi *left_child;
    struct Bi *right_child;
} Btree, *BtreePtr;

抽象數據結構(ADT):

void freeTree(BtreePtr b); //釋放節點

BtreePtr rightRotate(BtreePtr a); //右旋
BtreePtr leftRotate(BtreePtr a);  //左旋
BtreePtr leftRightRotate(BtreePtr a);  //左旋右旋
BtreePtr rightLeftRotate(BtreePtr a);  //右旋左旋

BtreePtr _checkHeight(BtreePtr a);   //判斷二叉樹是不是平衡
BtreePtr insertAVLTree(BtreePtr a, BtreePtr b);  //插入節點

完整代碼

#include <stdio.h>
#include <malloc.h>
#include <memory.h>
#define HEIGHT(p)    ( (p==NULL) ? 0 : (((BtreePtr)(p))->height) )
#define MAX(a, b)    ( (a) > (b) ? (a) : (b) )

typedef struct Bi{
    int val;
    int pos;

    int height;
    struct Bi *parent;
    struct Bi *left_child;
    struct Bi *right_child;
} Btree, *BtreePtr;

int midSearch(const BtreePtr a, const int key) {
    if (a != NULL) {
        if (key > a->val) {
            return midSearch(a->right_child, key);
        }
        else if(key < a->val) {
            return midSearch(a->left_child, key);
        }
        else {
            return a->pos;
        }
    }
    else {
        return -1;
    }
}

void freeTree(BtreePtr b) {
    if (b->right_child !=NULL) {
        freeTree(b->right_child);
    }
    if (b->left_child != NULL) {
        freeTree(b->left_child);
    }
}

BtreePtr rightRotate(BtreePtr a) {
    BtreePtr b = (BtreePtr)malloc(sizeof(Btree));

    b = a->left_child;
    b->parent = a->parent;
    a->left_child = b->right_child;
    b->right_child = a;

    b->right_child->parent = b;

    a->height = MAX(HEIGHT(a->left_child), HEIGHT(a->right_child)) + 1;
    b->height = MAX(HEIGHT(b->left_child), a->height) + 1;

    return b;
}

BtreePtr leftRotate(BtreePtr a) {
    BtreePtr b = (BtreePtr)malloc(sizeof(Btree));;

    b = a->right_child;
    a->right_child = b->left_child;
    b->left_child = a;

    b->parent = a->parent;
    b->left_child->parent = b; //

    a->height = MAX(HEIGHT(a->left_child), HEIGHT(a->right_child)) + 1;
    b->height = MAX(HEIGHT(b->right_child), a->height) + 1;
    return b;
}

BtreePtr rightLeftRotate(BtreePtr a) {
    a->right_child = rightRotate(a->right_child);
    a = leftRotate(a);
    return a;
}

BtreePtr leftRightRotate(BtreePtr a) {
    a->left_child = leftRotate(a->left_child);
    a = leftRotate(a);
    return a;
}

BtreePtr _checkHeight(BtreePtr a) {
    int left = HEIGHT(a->left_child);
    int right = HEIGHT(a->right_child);


    if (right - left > 1) {  //一個節點的左右子樹高度差不能大於2
        if (HEIGHT(a->right_child->right_child) - HEIGHT(a->right_child->left_child)>0){  //右節點高度大於左節點高度
            a = leftRotate(a); //同方向旋轉
        }
        else {
            a = rightLeftRotate(a); //異方向旋轉
        }
    }
    if (left - right > 1) {
        if (HEIGHT(a->left_child->right_child) - HEIGHT(a->left_child->left_child)>0) {
            a = leftRightRotate(a); //異方向旋轉
        }
        else {  //左節點高度大於右節點高度
            a = rightRotate(a); //同方向旋轉
        }
    }

    return a;
}

BtreePtr insertAVLTree(BtreePtr a, BtreePtr b) {
    //new value in b
    if (a->height == 0) {
        *a = *b;  //不能用a = b, copy b中所有內容
        //puts("hello");
        free(b);
    }
    else {
        if (a->val < b->val) {
            if (a->right_child != NULL) {
                b->parent = a->right_child;

                a->right_child = insertAVLTree(a->right_child, b);
            }
            else {
                b->parent = a;

                a->right_child = b;  //不能用 *(a-> right_child) = *b
            }
        }
        else {
            if (a->left_child != NULL) {
                b->parent = a->left_child;

                a->left_child = insertAVLTree(a->left_child, b);
            }
            else {
                b->parent = a;

                a->left_child = b; //不能用 *(a-> left_child) = *b
            }
        }

        //節點高度
        if (a->left_child != NULL) {
            if (a->left_child->height == a->height) {
                (a->height)++;
            }
        }
        if (a->right_child != NULL) {
            if (a->right_child->height == a->height) {
                (a->height)++;
            }
        }

        a = _checkHeight(a);

    }
    return a;
}


int AVLTreeSearch(const int *a, const int length, const int key) {
    BtreePtr root = (BtreePtr)malloc(sizeof(Btree));;
    memset(root, 0, sizeof(Btree));  //將結構體中的指針初始化
    for (int i = 0; i < length; i++) {
        BtreePtr p = (BtreePtr)malloc(sizeof(Btree));
        memset(p, 0, sizeof(Btree));
        p->val = a[i];
        p->pos = i;
        p->height = 1;
        root = insertAVLTree(root, p);  //構建二叉樹
    }
    int pos = midSearch(root, key);
    freeTree(root); //不能直接使用free(b)
    return pos;
}



void main() {
    const int length = 6;
    int my_array[6] = { 1 ,7, 6, 8, 0,1 };
    printf("%d \n", AVLTreeSearch(my_array, length, 6));
}
發佈了33 篇原創文章 · 獲贊 13 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章