本来之前已经发了AVL树的插入,结果续写AVL树的删除时发现之前写的AVL插入有bug,于是乎将其删除了。折腾了一周多,终于将AVL树搞定了。。。不容易啊
//AVLTree.h
#ifndef _AVLTREE_H_
#define _AVLTREE_H_
#include <stdlib.h>
typedef int Element;
typedef struct _AVLTreeNode
{
Element Data;
int BF; //平衡因子
struct _AVLTreeNode *Parent; //指向双亲节点,用于回溯,也可以不含此指针,而通过栈来保存插入路径
struct _AVLTreeNode *LChild;
struct _AVLTreeNode *RChild;
}AVLTreeNode;
typedef AVLTreeNode *AVLTree;
void AVLInit(AVLTree *tree);
bool AVLInsert(AVLTree *tree, Element v);
AVLTreeNode *CreateNode(Element v);
void RotateL(AVLTree *AVLTreeRoot);
void RotateR(AVLTree *AVLTreeRoot);
void RotateLR(AVLTree *AVLTreeRoot);
void RotateRL(AVLTree *AVLTreeRoot);
bool AVLDelete(AVLTree *tree, Element v);
#endif // _AVLTREE_H_
//AVLTree.c
#include "AVLTree.h"
void AVLInit(AVLTree *tree)
{
*tree = NULL;
}
AVLTreeNode *CreateNode(Element v)
{
AVLTreeNode *q = (AVLTreeNode *)malloc(sizeof(AVLTreeNode));
if( NULL == q )
return NULL;
q->Data = v;
q->BF = 0;
q->Parent = q->LChild = q->RChild = NULL;
return q;
}
bool AVLInsert(AVLTree *tree, Element v)
{
if( NULL == *tree )
{
AVLTreeNode *q = CreateNode(v);
if( NULL == q )
return false;
*tree = q;
}
else
{
AVLTreeNode *s = NULL; //用于存储最小不平衡子树的双亲节点
AVLTreeNode *n = *tree;
AVLTreeNode *p = NULL; //用于记录插入路径
while (NULL != n) //循环用于寻找新节点应该插入的位置
{
if( v > n->Data )
{
p = n;
n = n->RChild;
}
else if( v < n->Data )
{
p = n;
n = n->LChild;
}
else //不能插入相同值
return false;
}
n = CreateNode(v);
if( NULL == n )
return false;
if( v > p->Data )
p->RChild = n; //挂接新节点
else
p->LChild = n;
n->Parent = p; //记录双亲节点,便于回溯调整平衡因子
while (NULL != p) //从最新插入的节点开始向上回溯以调整平衡因子
{
if( p->LChild == n )
p->BF++;
else
p->BF--;
if( -1 == p->BF || 1== p->BF ) //不知祖双亲节点的情况,回溯
{
n = p;
p = p->Parent;
}
else if( 0 == p->BF ) //双亲节点是平衡的则无需回溯
break;
else //不平衡则立刻旋转
{
s = p->Parent;
if( p->BF > 0 && n->BF > 0 )
RotateR(&p); //BF同号且大于0,右旋转以降低左树高
else if( p->BF < 0 && n->BF < 0 )
RotateL(&p);
else if( p->BF > 0 && n->BF < 0 )
RotateLR(&p); //BF异号,最小不平衡子树BF大于0,先左再右旋转
else
RotateRL(&p);
if( NULL == s ) //s为NULL说明原来的p(即传入旋转函数时的p)为整棵树的根,p不为整颗树的根在旋转函数中处理了
*tree = p; //将新根作为整棵树的根
break; //修改平衡后无需继续回溯
}
}
}
return true; //树平衡
}
void RotateL(AVLTree *AVLTreeRoot)
{
AVLTreeNode *GrandParent = (*AVLTreeRoot)->Parent; //最小不平衡子树根的双亲节点
AVLTreeNode *Parent = (*AVLTreeRoot)->RChild; //旋转完成之后的树根;
AVLTreeNode *SubLeft = *AVLTreeRoot; //旋转完成之后的左子树;
SubLeft->RChild = Parent->LChild; //Parent节点可能存在左子树,先保存
if( NULL != Parent->LChild ) //如果确实存在
Parent->LChild->Parent = SubLeft; //修改其双亲节点
Parent->LChild = SubLeft; //左旋转
SubLeft->Parent = Parent; //修改双亲点
Parent->BF = SubLeft->BF = 0; //修改平衡因子
if( NULL != GrandParent && GrandParent->LChild == *AVLTreeRoot ) //将最小不平衡子树的双亲节点与旋转完成后的树根连接起来
GrandParent->LChild = Parent;
if( NULL != GrandParent && GrandParent->RChild == *AVLTreeRoot )
GrandParent->RChild = Parent;
*AVLTreeRoot = Parent; //更改树根
Parent->Parent = GrandParent; //新树根的双亲节点
}
void RotateR(AVLTree *AVLTreeRoot)
{
AVLTreeNode *GrandParent = (*AVLTreeRoot)->Parent;
AVLTreeNode *Parent = (*AVLTreeRoot)->LChild;
AVLTreeNode *SubRight = *AVLTreeRoot;
SubRight->LChild = Parent->RChild;
if( NULL != Parent->RChild )
Parent->RChild->Parent = SubRight;
Parent->RChild = SubRight;
SubRight->Parent = Parent;
Parent->BF = SubRight->BF = 0;
if( NULL != GrandParent && GrandParent->LChild == *AVLTreeRoot )
GrandParent->LChild = Parent;
if( NULL != GrandParent && GrandParent->RChild == *AVLTreeRoot )
GrandParent->RChild = Parent;
*AVLTreeRoot = Parent;
Parent->Parent = GrandParent;
}
void RotateLR(AVLTree *AVLTreeRoot)
{
AVLTreeNode *GrandParent = (*AVLTreeRoot)->Parent;
AVLTreeNode *SubRight = *AVLTreeRoot;
AVLTreeNode *SubLeft = (*AVLTreeRoot)->LChild;
AVLTreeNode *Parent = SubLeft->RChild;
SubLeft->RChild = Parent->LChild; //保存Parent可能存在的左子树
if( NULL != Parent->LChild ) //如果确实存在
Parent->LChild->Parent = SubLeft; //修改其双亲节点
Parent->LChild = SubLeft; //左旋转
SubLeft->Parent = Parent;
SubRight->LChild = Parent->RChild; //保存Parent可能存在的右子树
if( NULL != Parent->RChild ) //确实存在
Parent->RChild->Parent = SubRight; //修改其双亲节点
Parent->RChild = SubRight; //右旋转
SubRight->Parent = Parent;
if( 0 == Parent->BF ) //查看Parent旋转之前的子树情况,其BF为0时为前篇博客所诉的情况1
SubRight->BF = SubLeft->BF = 0; //Parent已平衡,无需调整
else if( 1 == Parent->BF ) //情况2且Parent旋转之前仅有左子树
{
SubLeft->BF = 0;
SubRight->BF = -1;
Parent->BF = 0;
}
else //情况2且Parent旋转之前仅有右子树
{
SubLeft->BF = -1;
SubRight->BF = 0;
Parent->BF = 0;
}
if( NULL != GrandParent && GrandParent->LChild == *AVLTreeRoot ) //将最小不平衡子树的双亲节点与旋转完成后的树根连接起来
GrandParent->LChild = Parent;
if( NULL != GrandParent && GrandParent->RChild == *AVLTreeRoot )
GrandParent->RChild = Parent;
*AVLTreeRoot = Parent; //更改树根
Parent->Parent = GrandParent;
}
void RotateRL(AVLTree *AVLTreeRoot)
{
AVLTreeNode *GrandParent = (*AVLTreeRoot)->Parent;
AVLTreeNode *SubLeft = *AVLTreeRoot;
AVLTreeNode *SubRight = SubLeft->RChild;
AVLTreeNode *Parent = SubRight->LChild;
SubRight->LChild = Parent->RChild;
if( NULL != Parent->RChild )
Parent->RChild->Parent = SubRight;
Parent->RChild = SubRight;
SubRight->Parent = Parent;
SubLeft->RChild = Parent->LChild;
if( NULL != Parent->LChild )
Parent->LChild->Parent = SubLeft;
Parent->LChild = SubLeft;
SubLeft->Parent = Parent;
if( 0 == Parent->BF )
SubLeft->BF = SubRight->BF = 0;
else if( 1 == Parent->BF )
{
SubLeft->BF = 0;
SubRight->BF = 1;
Parent->BF = 0;
}
else
{
SubLeft->BF = 1;
SubRight->BF = 0;
Parent->BF = 0;
}
if( NULL != GrandParent && GrandParent->LChild == *AVLTreeRoot )
GrandParent->LChild = Parent;
if( NULL != GrandParent && GrandParent->RChild == *AVLTreeRoot )
GrandParent->RChild = Parent;
*AVLTreeRoot = Parent;
Parent->Parent = GrandParent;
}
bool AVLDelete(AVLTree *tree, Element v)
{
AVLTreeNode *p = *tree; //意图删除节点
AVLTreeNode *q = NULL; //意图删除节点的子节点
AVLTreeNode *pp = NULL; //意图删除节点的双亲节点
AVLTreeNode *s = NULL; //用于存储最小不平衡子树的双亲节点
int flag = 0; //左右子树标记,此标记为必须的,用于避免意图删除节点的双亲的另一子树为NULL且意图删除节点的子树也为NULL时影响判断
while (NULL != p)
{
if( p->Data == v )
break;
else if( p->Data > v )
p = p->LChild;
else
p = p->RChild;
}
if( NULL == p ) //节点不存在或树为空
return false;
if( NULL != p->LChild && NULL != p->RChild ) //节点存在左右子树,转化为最多存在一个子树的情况再删除,此处转化为删除p右子树中最小节点
{
q = p->RChild;
while (NULL != q->LChild)
q = q->LChild;
p->Data = q->Data;
p = q;
}
//最多存在一个子树
pp = p->Parent;
if( NULL == pp ) //删除只有一个节点的AVL树(节点存在但其双亲节点不存在,意图删除节点必是树根)
{
free(p);
*(tree) = NULL;
return true;
}
//寻找可能存在节点的子树q以备以后挂接
if( NULL == p->LChild )
q = p->RChild;
else
q = p->LChild;
if( pp->LChild == p) //意图删除的节点为其双亲节点的左子树
{
pp->LChild = q; //用其可能存在的子树将其替换
flag = 1;
}
else
{
pp->RChild = q;
flag = -1;
}
if( NULL != q ) //修改其子树的双亲节点
q->Parent = pp;
free(p); //释放
while (NULL != pp) //回溯
{
if( q == pp->LChild && 1 == flag ) //被删的节点在其双亲节点的左子树
pp->BF--;
if( q == pp->RChild && -1 == flag )
pp->BF++;
if( 1 == pp->BF || -1 == pp->BF ) //只是双亲节点的一边的子树缩短了一点,其所在树高度无变化,整体树依旧平衡
break;
else if( 0 == pp->BF ) //双亲节点树高度变化,继续回溯查看上层情况,查看是否影响上层平衡
{
q = pp;
pp = pp->Parent;
if( NULL != pp && pp->LChild == q) //从双亲左子树回溯
flag = 1;
else
flag = -1;
}
else //双亲较低子树高度降低,树本身已不平衡
{
s = pp->Parent;
if( pp->BF > 0 ) //令q指向双亲的较高子树
q = pp->LChild;
else
q = pp->RChild;
if( pp->BF > 0 )
{
if( q->BF > 0 ) //右单旋转
{
RotateR(&pp);
}
else if( q->BF = 0 ) //右单旋转,且需要额外更改平衡因子
{
RotateR(&pp);
pp->BF = -1;
q->BF = 1;
}
else //先左后右旋转
{
RotateLR(&pp);
}
}else
{
if( q->BF > 0 ) //先右后左旋转
{
RotateRL(&pp);
}
else if( q->BF = 0 ) //左单旋转,且需额外更改平衡因子
{
RotateL(&pp);
pp->BF = 1;
q->BF = -1;
}
else //左单旋转
{
RotateL(&pp);
}
}
if( NULL == s ) //s为NULL说明原来的p(即传入旋转函数时的p)为整棵树的根,p不为整颗树的根在旋转函数中处理了
*tree = pp; //将新根作为整棵树的根
}
}
return true;
}
//main.c
#include "AVLTree.h"
#include "stdio.h"
int main()
{// Element a[] = {100, 10, 66, 87, 90, 60, 32, 55, 0, 99};
// Element a[] = {0, 1, 2 ,3, 4, 5, 6, 7, 8, 9};
// Element a[] = { 99, 88,77, 66, 55, 44, 33, 22 };
Element a[] = {60, 40, 70, 30, 50, 65, 80, 20, 35, 45, 55, 68, 75, 90, 15, 43, 48, 58, 85, 42};
int t = sizeof(a) / sizeof(Element);
AVLTree tree;
bool ret = false;
AVLInit(&tree);
for(int i=0; i<t; i++)
AVLInsert(&tree, a[i]);
ret = AVLDelete(&tree, 20);
if( false == ret )
printf("节点不存在或树为空\n");
system("pause");
return 1;
}