【问题标题】:Inserting AVL tree in C在 C 中插入 AVL 树
【发布时间】:2019-04-06 00:50:21
【问题描述】:

我正在实现 AVL 树及其旋转等操作。
最后,当我尝试插入一个数组时,结果似乎
不同。任何人都告诉我出了什么问题!谢谢!

#include <stdio.h>
#include <stdlib.h>
#define LH +1   
#define RH -1   
#define EQ 0
typedef int BOOL;
typedef struct node
{
    int bf;   
    struct node *left;
    struct node *right;
    int val;
}treeNode;  
void L_Rotate(treeNode **T)
{
    treeNode *p = (*T)->right;  
    (*T)->right = p->left;  
    p->left=*T;
    *T=p;
}
void R_Rotate(treeNode **T) 
{
    treeNode *p=(*T)->left;  
    (*T)->left=p->right;   
    p->right=*T;  
    *T=p; 
}
void Left_Balance(treeNode **T)
{
    treeNode *p=(*T)->left;
    treeNode *q;
    switch(p->bf)
    {
        case LH:  
            p->bf=(*T)->bf=EQ;
            R_Rotate(T); 
            break;
        case RH:  
            q = p->right; 
            switch(q->bf)
           {
               case LH: 
                   (*T)->bf=RH;
                   p->bf=EQ;
                   break;
               case EQ: 
                   (*T)->bf=q->bf=EQ;
                   break;
               case RH: 
                   p->bf=LH;
                   (*T)=EQ;
                   break;
           }
            q->bf=EQ;
            L_Rotate(&p);
            R_Rotate(T);
    }
}
void Right_Balance(treeNode **T)
{
    treeNode *p=(*T)->right;
    treeNode *q;
    switch(p->bf)
    {
        case RH:
            (*T)->bf=p->bf=EQ;
            L_Rotate(T);
            break;
        case LH:
            q=p->left;
            switch(q->bf)
           {
               case LH:
                   (*T)->bf=EQ;
                   p->bf=RH;
                   break;
               case RH:
                   (*T)->bf=LH;
                   p->bf=EQ;
                   break;
           }
            q->bf=EQ;
            R_Rotate(&p);
            L_Rotate(T);
    }
}
int insertAVL (treeNode **T,int key, BOOL *taller)
{
    if(!*T)
    {
        *T=malloc(sizeof(treeNode));
        if(!*T) return 0;
        (*T)->left=(*T)->right=NULL;
        (*T)->bf=EQ;
        *taller = 1;
        (*T)->val=key;
    }
    else
    {
        if(key==(*T)->val)
        {
            *taller= 0;
            return 0;
        }
        else if(key<(*T)->val)
        {
            if(!insertAVL(&(*T)->left,key,taller))  return 0;
            if(*taller)
            {
                switch((*T)->bf)
                {
                    case LH:
                        Left_Balance(T);
                        *taller=0;
                        break;
                    case RH:
                        (*T)->bf=EQ;
                        *taller =0;
                        break;
                    case EQ:
                        (*T)->bf=LH;
                        *taller =1;
                        break;
                }
            }
        }
        else
        {
            if(!insertAVL(&(*T)->right,key,taller))  return 0;
            if(*taller)
            {
                switch((*T)->bf)
                {
                    case LH:
                        (*T)->bf=EQ;
                        *taller=0;
                        break;
                    case EQ:
                        (*T)->bf=RH;
                        *taller=1;
                        break;
                    case RH:
                        Right_Balance(T);
                        *taller =0;
                        break;
                }
            }
        }
    }
    return 1;
}
void preOrder(treeNode *T)
{
    if(!T)
    {
        return;
    }
    printf("%d\n",T->val);
    preOrder(T->left);
    preOrder(T->right);
}
int main() {
    int i;
    int a[10]={3,2,1,4,5,6,7,10,9,8};
    treeNode *T=NULL;

    BOOL taller;
    for(i=0;i<10;i++)
    {
        insertAVL(&T,a[i],&taller);
        preOrder(T);
        printf("-------\n");
    }

    return 0;
}

每次插入树后我都遍历了树,结果是
直到我将 9 插入树中。

【问题讨论】:

  • 调试树总是很困难且耗时,但有时您只需要这样做,并使用调试器逐步检查代码以找出出错的时间和位置。在这种情况下,这并不难,因为您知道插入9 时会出现问题,因此您可以跳过main 函数中的insertAVL 调用,直到到达@987654325 @。然后进入函数,进入所有递归调用,进入平衡函数。

标签: c insert avl-tree


【解决方案1】:

当您修改树(或子树)时,您传入一个指向头指针的指针,以便更改反映在原始链接中,无论是全局头还是节点的左/右链接之一。在我看来,这是一个很好的做法。

当你平衡树时,你会做同样的事情,但有一个陷阱:

treeNode *p = (*T)->left;

// ... some stuff ...

L_Rotate(&p);
R_Rotate(T);

这里,p(*T)-&gt;left 的本地副本。您最终修改了一个局部变量(它将立即超出范围),但不是父节点中的实际链接;节点被“吃掉”了。

您也可以将p 设为treeNode **,或者,如果您不更改指针本身,请将您的轮换代码更改为:

L_Rotate(&(*T)->left);
R_Rotate(T);

另一个轮换也是如此。

【讨论】:

  • 您的平衡左/右函数不对称,右平衡代码错过了EQ 的情况。也许这值得研究。
  • (有些人喜欢将.left.right替换为.link[2],这样他们只需编写一次带有方向指示器的旋转和平衡代码。)
【解决方案2】:

我还注意到您的平衡左/右功能不是对称的,并且右平衡代码错过了 EQ 案例。我做了一些尝试来添加它并将Right_Balance 重写为与Left_Balance 对称,但这没有解决任何问题。问题不(仅)在这里。

如果我管理 AVL 没有错,您必须考虑每个单元格的 高度 来决定在插入新值后如何平衡。

在您的情况下,没有 heightbf 能够以 bf 的方式获得 3 个值 LH/RH/EQ相当于从 1 到 3 范围内的高度。但是在插入 10 之后,值为 4 的单元格实际上具有高度 4,你无法管理它,对我来说这就是为什么你不能在 10 之后正确插入 9。

【讨论】:

    猜你喜欢
    • 2021-07-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多