上一篇文章,写了平衡二叉树的创建与基本操作
https://blog.youkuaiyun.com/m0_74214501/article/details/129205611
本篇文章主要写平衡二叉树的删除。
思路讲解:
这里先说一下总的思路:平衡二叉树要求绝对平衡,我们在删除的过程中不可以打破平衡,所以我们的程序在编写的时候就要着重于维持平衡的操作。
首先我们在每次从删除的时候。就要设计一个刷新结点高度的步骤,同时又因为整个树都需要刷新,所以只有递归的操作,可实现这个需要。
其次在有一种特殊的情况下(就是下文的第三种情况)我们也需要设计一个递归,来实现子树上最大值或者最小值的查找与高度刷新。
我们第一步用递归找到要删除的结点,并且在尾部有一个判断结点是否需要旋转的操作。
void Delete(AVL_Tree& A, int B)
{
if (A->data == B)
{
_Delete(A);
if (A == NULL)return;//这里需要注意
}
else if (A->data > B)
Delete(A->left, B);
else if (A->data < B)
Delete(A->right, B);
A->height = Height(A);
if (BF(A) == 2)
{
if (A->left != NULL && BF(A->left) == -1)
Leftmove(A->left);
Rightmove(A);
}
else if (BF(A) == -2)
{
if (A->right != NULL && BF(A->right) == 1)
Rightmove(A->right);
Leftmove(A);
}
}
这里要注意结点直接被删除而不是被替代的情况。如果结点直接被删除了,那么还进行旋转判断,就会报错,所以直接返回到上一层。
删除的具体操作
平衡二叉树的删除主要有三种情况
下文将要删除的结点称为根结点,非整棵树的根结点
第一种:删除结点的左右子树为空(直接删除结点)
这一种情况是最简单的,只需要将结点指针释放,赋为空指针即可。
if (A->left == NULL && A->right == NULL)
{
free(A); A = NULL; return;//赋值为空指针很重要。
}
第二种:删除的结点,左右结点有一个为空,另一个不为空(用左子树或者右子树代替)
这种情况,我们先创建一个指针,记录当前的结点指针,然后将当前结点的指针指向左右不为空的结点。之后释放之前创建的指针即可。
大概情况有两种,但是操作都类似
if (A->left != NULL && A->right == NULL)
{
AVL_Tree p = A;
A = A->left;
free(p);
}
else if (A->right != NULL && A->left == NULL)
{
AVL_Tree p = A;
A = A->right;
free(p);
}
第三种:当左右子树都不为空(关键情况)(用右子树上的最小值或者左子树上的最大值代替)
这种情况下,我们的方法是找到左子树上的最大结点或者右子树上的最小结点(简称a),将a的值赋到我们要删除的结点上,然后将a释放,将a置为空指针。
下面为找右子树上最小结点的方法:!
第一种情况:就是当根结点的右子树的左子树为空的时候,我们就不需要进入递归。直接将根结点的值赋为它的左子树的值,根结点的右子树指针赋为左子树的右子树。
if (parent == NULL)
{
A->right = p->right;
A->data = p->data;
free(p);
p = NULL;
}
第二种情况:当根结点的右子树的左子树不为空。我们就开始递归寻找最小值,直到左子树为空,结束递归,将根结点的data值赋为当前结点的值,将该结点的右子树赋为该结点的父结点的左子树,然后释放该结点,返回上一层。
需要注意的是,我们这一个递归操作的每一层有一个刷线高度、判断是否旋转的操作。以达到删除结点后,它的上层结点们的高度准确。
void Di_tui(AVL_Tree& A,AVL_Tree& p, AVL_Tree& parent)
{
if (p->left != NULL)
{
parent = p;
//千万不要像下面这样写:
//AVL_Tree H = p->left;
//Di_tui(A, H, parent);这在递归操作里面是大忌
Di_tui(A, p->left, parent);
}
else
{
if (parent == NULL)
{
A->right = p->right;
A->data = p->data;
free(p);
p = NULL;
}
else
{
A->data = p->data;
parent->left = p->right;
free(p);
p = NULL;
}
return;
}
p->height = Height(p);
if (BF(p) == 2)
{
if (p->left != NULL && BF(p->left) == -1)
Leftmove(p->left);
Rightmove(p);
}
else if (BF(p) == -2)
{
if (p->right != NULL && BF(p->right) == 1)
Rightmove(p->right);
Leftmove(p);
}
}
函数的参数有根结点,当前递归到的结点p,当前结点的父结点。
总代码删除代码:
void Di_tui(AVL_Tree& A, AVL_Tree& p, AVL_Tree& parent)
{
if (p->left != NULL)
{
parent = p;
//千万不要像下面这样写:
//AVL_Tree H = p->left;
//Di_tui(A, H, parent);这在递归操作里面是大忌
Di_tui(A, p->left, parent);
}
else
{
if (parent == NULL)
{
A->right = p->right;
A->data = p->data;
free(p);
p = NULL;
}
else
{
A->data = p->data;
parent->left = p->right;
free(p);
p = NULL;
}
return;
}
p->height = Height(p);
if (BF(p) == 2)
{
if (p->left != NULL && BF(p->left) == -1)
Leftmove(p->left);
Rightmove(p);
}
else if (BF(p) == -2)
{
if (p->right != NULL && BF(p->right) == 1)
Rightmove(p->right);
Leftmove(p);
}
}
void _Delete(AVL_Tree& A)
{
if (A->left == NULL && A->right == NULL)
{
free(A); A = NULL; return;//赋值为空指针很重要。
}
else if (A->left != NULL && A->right == NULL)
{
AVL_Tree p = A;
A = A->left;
free(p);
}
else if (A->right != NULL && A->left == NULL)
{
AVL_Tree p = A;
A = A->right;
free(p);
}
else if (A->left != NULL && A->right != NULL)
{
AVL_Tree p = A->right;
AVL_Tree parent = NULL;
Di_tui(A, p, parent);
}
}
void Delete(AVL_Tree& A, int B)
{
if (A->data == B)
{
_Delete(A);
if (A == NULL)return;
}
else if (A->data > B)
Delete(A->left, B);
else if (A->data < B)
Delete(A->right, B);
A->height = Height(A);
if (BF(A) == 2)
{
if (A->left != NULL && BF(A->left) == -1)
Leftmove(A->left);
Rightmove(A);
}
else if (BF(A) == -2)
{
if (A->right != NULL && BF(A->right) == 1)
Rightmove(A->right);
Leftmove(A);
}
}
测试代码:
typedef struct AVL_Node
{
int data;
int height;
struct AVL_Node* left;
struct AVL_Node* right;
}AVL_Node, *AVL_Tree;
int Height(AVL_Tree A)
{
if (A->left == NULL && A->right == NULL)
return 1;
else if (A->left != NULL && A->right == NULL)
return A->left->height + 1;
else if (A->right != NULL && A->left == NULL)
return A->right->height + 1;
else
return A->left->height > A->right->height ? A->left->height + 1 : A->right->height + 1;
}
int BF(AVL_Tree A)
{
if (A->left == NULL && A->right == NULL)
return 0;
else if (A->left != NULL && A->right == NULL)
return A->left->height;
else if (A->right != NULL && A->left == NULL)
return -A->right->height;
else
return A->left->height - A->right->height;
}
void Rightmove(AVL_Tree& A)
{
AVL_Tree New_node = A->left;
AVL_Tree Old_node = A;
Old_node->left = New_node->right;
New_node->right = Old_node;
Old_node->height = Height(Old_node);
New_node->height = Height(New_node);
A = New_node;
}
void Leftmove(AVL_Tree& A)
{
AVL_Tree New_node = A->right;
AVL_Tree Old_node = A;
Old_node->right = New_node->left;
New_node->left = Old_node;
Old_node->height = Height(Old_node);
New_node->height = Height(New_node);
A = New_node;
}
void Create_node(AVL_Tree& A, int B)
{
A = (AVL_Tree)malloc(sizeof(AVL_Node));
A->data = B;
A->height = 1;
A->left = A->right = NULL;
}
void Insert(AVL_Tree& A, int B)
{
if (A == NULL)
{
Create_node(A, B);
return;
}
if (A->data > B)
Insert(A->left, B);
else
Insert(A->right, B);
A->height = Height(A);
if (BF(A) == 2)
{
if (A->left != NULL && BF(A->left) == -1)
Leftmove(A->left);
Rightmove(A);
}
else if (BF(A) == -2)
{
if (A->right != NULL && BF(A->right) == 1)
Rightmove(A->right);
Leftmove(A);
}
}
void Create_Tree(AVL_Tree& A, int* arr, int num)
{
int rab = 0;
for (rab = 0; rab < num; rab++)
{
Insert(A, arr[rab]);
}
}
void In_order(AVL_Tree A)
{
if (A->left != NULL)
In_order(A->left);
printf("%d %d\n", A->data, A->height);
if (A->right != NULL)
In_order(A->right);
}
void Di_tui(AVL_Tree& A, AVL_Tree& p, AVL_Tree& parent)
{
if (p->left != NULL)
{
parent = p;
//千万不要像下面这样写:
//AVL_Tree H = p->left;
//Di_tui(A, H, parent);这在递归操作里面是大忌
Di_tui(A, p->left, parent);
}
else
{
if (parent == NULL)
{
A->right = p->right;
A->data = p->data;
free(p);
p = NULL;
}
else
{
A->data = p->data;
parent->left = p->right;
free(p);
p = NULL;
}
return;
}
p->height = Height(p);
if (BF(p) == 2)
{
if (p->left != NULL && BF(p->left) == -1)
Leftmove(p->left);
Rightmove(p);
}
else if (BF(p) == -2)
{
if (p->right != NULL && BF(p->right) == 1)
Rightmove(p->right);
Leftmove(p);
}
}
void _Delete(AVL_Tree& A)
{
if (A->left == NULL && A->right == NULL)
{
free(A); A = NULL; return;//赋值为空指针很重要。
}
else if (A->left != NULL && A->right == NULL)
{
AVL_Tree p = A;
A = A->left;
free(p);
}
else if (A->right != NULL && A->left == NULL)
{
AVL_Tree p = A;
A = A->right;
free(p);
}
else if (A->left != NULL && A->right != NULL)
{
AVL_Tree p = A->right;
AVL_Tree parent = NULL;
Di_tui(A, p, parent);
}
}
void Delete(AVL_Tree& A, int B)
{
if (A->data == B)
{
_Delete(A);
if (A == NULL)return;
}
else if (A->data > B)
Delete(A->left, B);
else if (A->data < B)
Delete(A->right, B);
A->height = Height(A);
if (BF(A) == 2)
{
if (A->left != NULL && BF(A->left) == -1)
Leftmove(A->left);
Rightmove(A);
}
else if (BF(A) == -2)
{
if (A->right != NULL && BF(A->right) == 1)
Rightmove(A->right);
Leftmove(A);
}
}
int main()
{
AVL_Tree root = NULL;
int arr[] = {1,2,3,45,6,78,9,10,26,48};
int num = sizeof(arr) / sizeof(arr[0]);
Create_Tree(root, arr, num);
Delete(root, arr[2]);
In_order(root);
return 0;
}
谢谢观看!!!有错误,多多指教!!!