问题描述
我需要在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;
}
}
}
解决方法
以下是显示右旋转所需的更改的图片:
通过将红色连接替换为绿色连接来完成旋转。
顶部的连接可能来自树中的较高节点(F
是该节点的左子节点或右子节点)。或者它是来自树的根指针的连接(如果F
是根节点)。为简单起见,rightRotate
的第一个参数应为指向节点的指针的指针。这样,什么指针指向F
都没有关系,代码只需更新该指针以指向D
。
在下面的代码中,第一行验证参数是否有效。第一个参数(指向指向F
的指针)不能为NULL。另外,F
和D
都必须存在。
使用断言检查参数以简化调试。无效的参数表示调用代码中存在问题。断言将导致调试器在该行停止(如果参数无效)。在调用堆栈中上移一层可以检查调用代码。
请注意,节点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;
}