AVL树左右旋转C

问题描述

我需要在AVL树上实现左右旋转。

结构为:

typedef struct tree mynode;   // 
struct tree{                    // tree node struct
int value;
int key;
char color;
struct tree *left;
struct tree *right;
};

我的问题是,在正确旋转之后,当我尝试访问node->left时,该程序由于分段错误而崩溃。 我认为旋转很好,但是我觉得如果它不保存指针...我的意思是我进行了旋转,但是它没有保存在左子树上。 右旋转:

mynode* rightRotate(mynode* root)
{
    mynode*tmp=(mynode*) malloc(sizeof(mynode));
    tmp->value=root->value;
    tmp->key=root->left->key;
    tmp->left=NULL;
    tmp->right=NULL;
    root->value=root->left->value;

    if(root->right==NULL)
      tmp->right=NULL;
    else if (root->right!=NULL)
      tmp->right=root->right;
    else printf("Error with right Rot\n");
    if (root->left->right==NULL)
      tmp->left=NULL;
    else if  (root->left->right!=NULL)
      tmp->left=root->left->right;
    else printf("Error with right Rot\n");
    root->right=tmp;

    mynode*tmp2;
    tmp2=root->left;
    root->left=root->left->left;
    free(tmp2); //freed old node
    printf("Rotation completed\n");
    return root;
}

我使用下面的功能只是为了检查前3个插入,我想要一棵带有两个子树的树,这就是为什么它检查左边还是右边是NULL

右旋转由调用

mynode* checkRotate(mynode*root)
{
    if(root->left==NULL) 
    {
        printf("Left rotate\n");
        root=leftRotate(root);
        return root; //to ensure parent-parent exists
    }
    else if (root->right==NULL) 
    {
        printf("Right rotate\n");
        root=rightRotate(root);
        return root; //to ensure parent-parent exists
    }
    else return NULL;
    return root;
}

调用

...some code...
root=checkRotate(root);
right->left->color=RED;//crashes here
...some code...

很明显,在检查右子树而不是左子树时,左旋转具有相同的问题。

编辑: 新的右旋转:

void rightRotate(mynode*root,mynode*son)
{
    if (son==NULL)
    {
        printf("Cannot rotate,son is null\n");
        return;
    }
    else 
    {
        if(son->left==NULL) 
        {
            printf("No left child,returning\n");
            return;
        }
        else 
        {
            mynode* F = son;
            mynode* D = son->left;
            if(son->left->right==NULL)
                son->left=NULL;
            else if (son->left != NULL)
                son->left = son->left->right;
            else {
                printf("Weird in right rotate\n");
            }
            D->right=son;
            if(root->right==son)
            {
                root->right=D;
                return ;
            }
            else if (root->left==son)
            {
                root->left=D;
                return ;
            }
            else 
            {
                printf("Error while setting new son in right balance\n");
                return ;
            }
            printf("Generic error in right balance\n");
            return;
        }
    }
}

解决方法

以下是显示右旋转所需的更改的图片:

enter image description here

通过将红色连接替换为绿色连接来完成旋转。

顶部的连接可能来自树中的较高节点(F是该节点的左子节点或右子节点)。或者它是来自树的根指针的连接(如果F是根节点)。为简单起见,rightRotate的第一个参数应为指向节点的指针的指针。这样,什么指针指向F都没有关系,代码只需更新该指针以指向D

在下面的代码中,第一行验证参数是否有效。第一个参数(指向指向F的指针)不能为NULL。另外,FD都必须存在。

使用断言检查参数以简化调试。无效的参数表示调用代码中存在问题。断言将导致调试器在该行停止(如果参数无效)。在调用堆栈中上移一层可以检查调用代码。

请注意,节点E是可选的,即D可能没有合适的孩子。如果E不存在,则D->right为NULL,并且代码会将F->left设置为NULL。 E不需要特殊处理。

代码如下:

void rightRotate(mynode **parentPtr,mynode *child)
{
    // make sure the arguments are valid for a right rotation
    assert(parentPtr != NULL && child != NULL && child->left != NULL);

    // save the three node addresses involved in the rotation
    mynode *F = child;
    mynode *D = F->left;
    mynode *E = D->right;

    // perform the rotation
    *parentPtr = D;
    D->right = F;
    F->left = E;
}