C语言 我的AVL插入速度很慢,我怎样才能使它更快?

k4ymrczo  于 2023-03-17  发布在  其他
关注(0)|答案(1)|浏览(118)

我正在尝试优化我的AVL树。如果没有自平衡,一百万个节点的树创建是超级快的。但是一旦我添加了旋转,它就变得非常慢。我怀疑这是由计算高度或平衡引起的,但是我无法找到正确的修复方法。
我应该做些什么来提高再平衡的效率?

typedef struct node{
    int value;
    struct node *left, *right, *parent;
}NODE;

int insert(int val,NODE **root,NODE *par){
    NODE *temp;
    NODE *new;

    if(*root == NULL){
        new = (NODE *)malloc(sizeof(NODE));
        new->value = val;
        new->left = NULL;
        new->right = NULL;
        new->parent = par;
        *root = new;
        rotate(*root);
        return 1;
    }

    temp = *root;
    if(val == temp->value){
        //printf("Node already exist\n"); //X
        return 0;
    }
    if(val < temp->value){
        insert(val,&temp->left,temp);
    }
    if(val > temp->value){
        insert(val,&temp->right,temp);
    }
}

void rotate(NODE* root){
    NODE* p;
    p = root;
    while(p != NULL){
        rotation(p);
        p = p->parent;
    }
}

void rotation(NODE *root){
    NODE* temp;
    int balance = get_balace(root);
    if(balance > 1){
        if(get_balace(root->left) >= 1){
            right_rotate(root);
        }else if(get_balace(root->left) <= -1){
            left_rotate(root->left);
            right_rotate(root);
        }
    }else if(balance < -1){
        if(get_balace(root->right) <= -1){
            left_rotate(root);
        }else if(get_balace(root->right) >= 1){
            right_rotate(root->right);
            left_rotate(root);
        }
    }
}

int get_height(NODE *root){
    int left_h, right_h;
    if(root == NULL){
        return 0;
    }
    left_h = get_height(root->left);
    right_h = get_height(root->right);
    return 1 + max(left_h,right_h);
}

int get_balace(NODE *root){
    return get_height(root->left) - get_height(root->right);
}

旋转函数仅仅是具有逻辑的基本旋转。
我试着改变balanceheight函数,通过分别计算left_hright_h而不是像return 1 + max(get_height(root->left),get_height(root->right));那样计算,我设法使height稍微快一些
还能做些什么来加快速度呢?

qyyhg6bp

qyyhg6bp1#

在AVL树中计算子树的高度(在插入节点之后)是没有效率的。更重要的是,不需要知道子树的高度来实现正确运行的AVL树。与每个节点一起存储平衡因子(bf)就足够了。每种类型的旋转都可以导出平衡因子的变化,以保持信息的一致性。
Wikipedia上关于AVL tree的文章详细介绍了旋转和保持平衡因子最新的算法,注意旋转函数有前提条件,只有在需要重新平衡树时调用它们时才能给予可靠的结果。
下面是一个实现:

typedef struct node {
    int value, bf;
    struct node *left, *right;
} Node;

Node* createNode(int val) {
    Node* newNode = (Node *) malloc(sizeof(Node));
    newNode->value = val;
    newNode->left = newNode->right = NULL;
    newNode->bf = 0;
    return newNode;
}

void rotateLeft(Node **x) {
    Node *z = (*x)->right;
    (*x)->right = z->left;
    z->left = *x;
    (*x)->bf = +!z->bf;
    z->bf = -(*x)->bf;
    *x = z;
}

void rotateRight(Node **x) {
    Node *z = (*x)->left;
    (*x)->left = z->right;
    z->right = *x;
    (*x)->bf = -!z->bf;
    z->bf = -(*x)->bf;
    *x = z;
}

void rotateRightLeft(Node **x) {
    Node *z = (*x)->right;
    Node *y = z->left;
    z->left = y->right;
    y->right = z;
    (*x)->right = y->left;
    y->left = *x;
    (*x)->bf = -(y->bf > 0);
    z->bf = +(y->bf < 0);
    y->bf = 0;
    *x = y;
}

void rotateLeftRight(Node **x) {
    Node *z = (*x)->left;
    Node *y = z->right;
    z->right = y->left;
    y->left = z;
    (*x)->left = y->right;
    y->right = *x;
    (*x)->bf = +(y->bf < 0);
    z->bf = -(y->bf > 0);
    y->bf = 0;
    *x = y;
}

#define ABSENT_BF 9
void insert(Node **node, int value) {
    if (!*node) {
        *node = createNode(value);
        return;
    }
    int side = value < (*node)->value ? -1 : 1;
    Node **child = side == -1 ? &((*node)->left) : &((*node)->right); 
    int origBF = *child ? (*child)->bf : ABSENT_BF;
    insert(child, value);
    if (origBF == ABSENT_BF || origBF == 0 && (*child)->bf != 0) { // Height changed
        if ((*node)->bf != side) { // The bf update will stay in range
            (*node)->bf += side; // Do it.
        // In all other cases a rotation is needed:
        } else if (side == -1) {
            if ((*child)->bf > 0) {
                rotateLeftRight(node); 
            } else {
                rotateRight(node);
            }
        } else {
            if ((*child)->bf < 0) {
                rotateRightLeft(node);
            } else {
                rotateLeft(node);
            }
        }
    }
}

相关问题