【问题标题】:C: Creating a AVL balanced TreeC:创建 AVL 平衡树
【发布时间】:2014-10-23 01:15:18
【问题描述】:

我正在尝试编写代码来创建 AVL 平衡二叉树。 目的是每次插入新节点时都要旋转子树以保持(AVL)平衡。

(一个节点的左子树中的所有值都必须小于这个节点的值; 一个节点的右子树中的所有值都必须高于这个节点值)

我刚刚编写的代码适用于以特定顺序插入的数字,但不适用于其他顺序。 例如,以下输入工作正常:

10 7 14 12 15 3 0 

16 8 20 14 23 0

这个不会:

10 7 3 15 12 14 0 

10 7 5 14 13 0

为什么?

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

typedef enum {false, true} Boolean;
typedef enum {minus = -1, zero, plus} balance;

typedef struct nohh {
    int info;
    balance bal;
    struct nohh *left;
    struct nohh *right;
} nohh, *noh;

void PrintTree(noh p);
Boolean Insert(noh *p, int x, Boolean *alt);
void RotateLL(noh p, noh p1);
void RotateLR(noh p, noh p1);
void RotateRR(noh p, noh p1);
void RotateRL(noh p, noh p1);

int main(){
    noh p = NULL;
    int x;
    Boolean check = false, *bol = &check;

    printf("int number ('0' to exit): ");
    scanf("%d", &x);

    do{
        check = Insert(&p, x, bol);
        printf("check = %d\n", check);

        printf("int number: ");
        scanf("%d", &x);
    }while(x != 0);

    PrintTree(p);

    return 0;
}

void PrintTree(noh p){
    printf("%d >> bal = %d\n", p->info, p->bal);
    if(p->left != NULL)
        PrintTree(p->left);
    if(p->right != NULL)
        PrintTree(p->right);
}

Boolean Insert(noh *p, int x, Boolean *alt){
    int info;

    if((*p)==NULL){
        *p = malloc(sizeof(nohh));
        (*p)->left = (*p)->right = NULL;
        (*p)->info = x;
        (*p)->bal = zero;
        *alt = true;
        return true;
    } else { /* if p isnt pointing to NULL */
        info = (*p)->info;
        if(x == info)
            return false;
        else if(x < info){ /* follow left */
            Boolean res = Insert(&(*p)->left, x, alt);
            if(!res)
                return false;
            if(*alt){ /* height increase */
                noh p1;
                switch((*p)->bal){
                case plus:
                    (*p)->bal = zero; *alt = false;
                    break;
                case zero:
                    (*p)->bal = minus; 
                    break;
                case minus: /* -1 -1 = -2 => not balanced!! */
                    p1 = (*p)->left;
                    if(p1->bal == minus){
                        /* Rotation LL */
                        RotateLL(*p, p1);
                        *alt = true;
                    } else if(p1->bal == plus){
                        /* Rotation LR */
                        RotateLR(*p, p1);
                        *alt = true;
                    } else {
                        /* Rotation LL */
                        RotateLL(*p, p1);
                        *alt = false;
                    }
                    p1->bal = zero; *alt = false;
                    break;
                }
            }
            return true;
        } else { /* follow right */
            Boolean res = Insert(&(*p)->right, x, alt);
            if(!res)
                return false;
            if(*alt){ /* height increase */
                noh p1;
                switch((*p)->bal){
                case minus:
                    (*p)->bal = zero; *alt = false;
                    break;
                case zero:
                    (*p)->bal = plus; 
                    break;
                case plus: /* 1 +1 = 2 => Not balanced! */
                    p1 = (*p)->right;
                    if(p1->bal == plus){
                        /* Rotation RR */
                        RotateRR(*p, p1);
                        *alt = true;
                    } else if(p1->bal == minus){
                        /* Rotation RL */
                        RotateRL(*p, p1);
                        *alt = true;
                    } else {
                        /* Rotation RR */
                        RotateRR(*p, p1);
                        *alt = false;
                    }
                    p1->bal = zero; *alt = false;
                    break;
                }
            }
            return true;
        }
    }
}

void RotateLL(noh p, noh p1){
    noh p2, aux;

    p2 = p1->left;

    aux = p;
    p = p1;
    p->right = aux;

    aux->left = aux->right = NULL;
    aux->bal = p2->bal = p->bal = zero;
}

void RotateLR(noh p, noh p1){
    noh p2, aux;
    aux = p;
    p2 = p1->right;

    p = p2;
    p2->left = p1;
    p2->right = aux;

    aux->left = aux->right = NULL;
    p1->left = p1->right = NULL;
    aux->bal = p1->bal = p->bal = zero;
}

void RotateRR(noh p, noh p1){
    noh p2, aux;

    p2 = p1->right;

    aux = p;
    p = p1;
    p->left = aux;

    aux->left = aux->right = NULL;
    aux->bal = p2->bal = p->bal = zero;
}

void RotateRL(noh p, noh p1){
    noh p2, aux;
    aux = p;
    p2 = p1->left;

    p = p2;
    p2->right = p1;
    p2->left = aux;

    aux->left = aux->right = NULL;
    p1->left = p1->right = NULL;

    aux->bal = p1->bal = p->bal = zero;
}

【问题讨论】:

    标签: c avl-tree tree-balancing


    【解决方案1】:

    您的 RotateLL/LR/RL/RR 实现存在缺陷——它们正确地调整了参与旋转的节点之间的指针,但它们没有更改指向旧根节点的指针。这会导致发生旋转时节点丢失。

    如果您在main() 的循环内插入对PrintTree() 的调用,您将看到发生了什么。例如:

    int number ('0' to exit): 1
    check = 1
    1 >> bal = 0
    int number: 2
    check = 1
    1 >> bal = 1
    2 >> bal = 0
    int number: 3
    check = 1
    1 >> bal = 0
    

    让每个 Rotate 函数返回一个指向新根节点的指针,并在Insert() 中适当地更新指针可能是最简单的。请记住,在某些情况下Insert() 需要更新*p 以反映根节点已移动的事实!

    【讨论】:

    • 谢谢@duskwuff。这似乎解决了这部分问题。我还不能让树保持平衡。我将把新代码放在下面。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-14
    • 1970-01-01
    • 2010-09-13
    • 2014-01-29
    相关资源
    最近更新 更多