用C实现AVL树

92dk7w1h  于 12个月前  发布在  其他
关注(0)|答案(2)|浏览(67)

我试图实现一个数组到BST,打印出BST(前序)后,我平衡它(AVL树与前序输出)。

#include <stdio.h>
#include <stdlib.h>

struct node {
    int data;
    struct node *left;
    struct node *right;
    int height;
};

struct node *new_node(int data) {
    struct node *nn = (struct node *)malloc(sizeof(struct node));
    nn->data = data;
    nn->left = NULL;
    nn->right = NULL;
    nn->height = 1;

    return nn;
}

struct node *insert(struct node *root, int data) {
    if (root == NULL)
        return new_node(data);
    else {
        if (data < root->data)
            root->left = insert(root->left, data);
        if (data > root->data)
            root->right = insert(root->right, data);
        return root;
    }
}

void pre_order(struct node *root) {
    if (root != NULL) {
        printf("%d ", root->data);
        pre_order(root->left);
        pre_order(root->right);
    }
}

int height(struct node *n) { 
    if (n == NULL) 
        return 0; 
    return n->height; 
} 

int max(int a, int b) 
{ 
    return (a > b) ? a : b; 
} 

struct node *rightRotate(struct node *y) 
{ 
    struct node *x = y->left; 
    struct node *T2 = x->right; 

    x->right = y; 
    y->left = T2; 

    y->height = max(height(y->left), height(y->right)) + 1; 
    x->height = max(height(x->left), height(x->right)) + 1; 

    return x; 
} 

struct node *leftRotate(struct node *x) { 
    struct node *y = x->right; 
    struct node *T2 = y->left; 

    y->left = x; 
    x->right = T2; 

    x->height = max(height(x->left), height(x->right)) + 1; 
    y->height = max(height(y->left), height(y->right)) + 1; 

    return y; 
} 

int getBalance(struct node *n) { 
    if (n == NULL) 
        return 0; 
    return height(n->left) - height(n->right); 
} 

struct node *AVLbalance(struct node *root, int data) 
{ 
    root->height = 1 + max(height(root->left), 
                           height(root->right)); 

    int balance = getBalance(root); 

    // Left Left Case 
    if (balance > 1 && data < root->left->data) 
        return rightRotate(root); 

    // Right Right Case 
    if (balance < -1 && data > root->right->data) 
        return leftRotate(root); 

    // Left Right Case 
    if (balance > 1 && data > root->left->data) 
    { 
        root->left = leftRotate(root->left); 
        return rightRotate(root); 
    } 

    // Right Left Case 
    if (balance < -1 && data < root->right->data) 
    { 
        root->right = rightRotate(root->right); 
        return leftRotate(root); 
    } 

    return root; 
} 

int main() {
    struct node *root = NULL;

    int arr[] = { 5, 7, 2, 4, 6 };
    int n = sizeof(arr) / sizeof(arr[0]); 

    for (int i = 0; i < n; i++)
        root = insert(root, arr[i]);

    printf("BST Pre-order:\n");
    pre_order(root);

    for (int j = 0; j < n; j++)
       root = AVLbalance(root, arr[j]);
        
    printf("\nBalanced (AVL) Pre-order:\n");
    pre_order(root);

    return 0;
}

字符串
在尝试了几个小时后,我不知道树在被调用时是否在平衡自己。是否有逻辑错误?程序编译时没有任何警告或错误。帮助!

inn6fuwd

inn6fuwd1#

主要的问题是,您依赖nn->height来平衡树,但在插入新节点时没有更新节点高度。
你可以这样修改插入函数:

struct node *insert(struct node *root, int data) {
    if (root == NULL)
        return new_node(data);
    else {
        if (data < root->data)
            root->left = insert(root->left, data);
        if (data > root->data)
            root->right = insert(root->right, data);
        root->height = max(height(root->left), height(root->right)) + 1;
        return root;
    }
}

字符串
但这还不够:函数AVLbalance仅处理树的根节点,因此在插入所有值之后重新平衡树不起作用。
当检测到不平衡时,应该在insert函数中重新平衡子树,即当在子树中插入data时,增加子树的高度超过另一个子树的长度+1.保持每个节点的高度是多余的。每个子树的一个比特表示它已经高于它的兄弟应该足以检测insert中重新平衡的需要。让树一直保持平衡
下面是insert函数的简单实现,它在插入时重新平衡树:

struct node *insert(struct node *root, int data) 
{ 
    if (root == NULL) 
        return new_node(data); 
  
    if (data < root->data) 
        root->left  = insert(root->left, data); 
    else if (data > root->data) 
        root->right = insert(root->right, data); 
    else
        return root; 
  
    root->height = 1 + max(height(root->left), 
                           height(root->right)); 
  
    // Handle 4 potential cases of imbalance:
    int balance = height(root->left) - height(root->right); 
    if (balance > 1) {
        if (data < root->left->data) {
            // Left Left Case 
            return rightRotate(root); 
        }
        if (data > root->left->data) {
            // Left Right Case 
            root->left = leftRotate(root->left); 
            return rightRotate(root); 
        }
    } else
    if (balance < -1) {
        if (data < root->right->data) {
            // Right Left Case 
            root->right = rightRotate(root->right); 
            return leftRotate(root); 
        } 
        if (data > root->right->data) {
            // Right Right Case 
            return leftRotate(root); 
        }
    }
    // No imbalance
    return root; 
}

mutmk8jj

mutmk8jj2#

你过度解读了自我平衡。

  • 自平衡搜索树 * 意味着 * 对于客户端代码 *,使用“通常的接口例程”就足以保持树的平衡。

这并不意味着保持平衡而不将其编码在树例程中。
在每个节点中保留可能有助于保持/恢复平衡的信息是不够的:
在每次修改操作结束时需要保证平衡
(插入、删除、合并/合并、拆分.)。

相关问题