定义结构体
#define Type int
typedef struct AVLNode {
Type data;
AVLNode* leftchild;
AVLNode* rightchild;
int bf;//平衡因子
}AVLNode;
typedef struct AVLTree {
AVLNode* root;
}AVLTree;
插入结点
void InitAVLTree(AVLTree* avl) {
avl->root = NULL;
}
bool Insert(AVLTree* avl, Type x) {
return Insert(avl->root, x);
}
bool Insert(AVLNode* &t, Type x) {
AVLNode* parent = NULL;
AVLNode* p = t;
LinkStack st;
InitStack(&st);
while (p != NULL) {//如果存在根节点,就从根的左右子树找
if (x == p->data)
return 0;
parent = p;
Push(&st, parent);
if (x < p->data)
p = p->leftchild;
else
p = p->rightchild;
}
//1.首先判断根节点是否为空,如果为空,为新插入的结点开辟空间
p = CreateNode(x);
if (parent==NULL) {
t = p;
return 1;
}
else
{
if (x < parent->data) {
parent->leftchild = p;
}
else {
parent->rightchild = p;
}
}
//2.设置平衡因子bf
while (!IsEmpty(&st))
{
parent = GetTop(&st);
Pop(&st);
if (parent->leftchild == p) {
parent->bf--;
}
else {
parent->bf++;
}
if (parent->bf == 0) break;
if (parent->bf == 1 || parent->bf == -1) {
p = parent;
}
else {
//3.开始旋转操作
int flag = (parent->bf < 0) ? -1 : 1;
if (p->bf == flag) {//单旋
if (flag == -1)
RotateR(parent);
else
RotateL(parent);
}
else {//双旋
if (flag == 1)
RotateRL(parent);
else
RotateLR(parent);
}
break;
}
}
//4.设置父结点的位置
if (IsEmpty(&st)) {//栈为空,根就是父节点
t = parent;
}
else {
AVLNode* q = GetTop(&st);//q是调整那个失衡节点之后的新子树根节点的父节点
if (q->data > parent->data)
q->leftchild = parent;
else
q->rightchild = parent;
}
return 1;
}
/*测试*/
void main() {
AVLTree avl;
InitAVLTree(&avl);
//int arr[] = { 50,40,60,10,45,70,5,30,20 };
int arr[] = {30,20,50,10,40,70,60,80,65 };
for (int i = 0; i < sizeof(arr)/sizeof(int); i++)
{
Insert(&avl, arr[i]);
}
Insert(&avl, 100);
}
分析
插入结点并设置父结点
插入第一个结点时,指针p都是指向新插入的节点。一开始,p=NULL,于是创建结点

插入第二个节点:p!=NULL,确定插入p的左子树还是右子树,p再次=NULL,于是创建结点。此时有父节点,让p根据大小指向父节点的左孩子

插入第三个节点,同样的创建结点,让p指向这个新结点之前,让parent指向p这个节点,成为新插入这个节点的父节点

调整平衡因子(借助栈)
让父结点入栈(30先入栈,其次是24),如果插入的节点是在这个结点的父节点的右边,父结点的bf++,反之bf–。

当父结点的bf=1或-1时,还要上溯到父节点的父节点。如24的bf为1,这时

此时栈中还有一个父节点30,所以这时让parent指向30,并把30出栈,栈空,然后parent(即30)的bf再次–等于-2
这时parent的bf既不是1,-1,也不是0。即找到了那一个使树不平衡的结点,所以就要开始旋转操作,使树恢复平衡。
旋转之后,找到调整那个失衡节点之后的新子树根节点的父节点,把旋转之后的新子树放在根节点的左右树。至此插入完成。
删除结点
旋转函数
针对的是第一个不平衡的节点进行旋转
右单旋
void RotateR(AVLNode* &ptr) {
AVLNode* subR = ptr;
ptr = subR->leftchild;
//1.ptr的右孩子赋值给根节点的的左孩子
subR->leftchild = ptr->rightchild;
//2.原来的根节点变成ptr的右孩子,ptr成为根节点
ptr->rightchild = subR;
ptr->bf = subR->bf = 0;
}


左单旋
void RotateL(AVLNode* &ptr) {
AVLNode* subR = ptr;
ptr = subR->rightchild;
subR->rightchild = ptr->leftchild;
ptr->leftchild = subR;
ptr->bf = subR->bf = 0;
}

先左后右双旋
void RotateLR(AVLNode* &ptr) {
AVLNode* subR = ptr;
AVLNode* subL = ptr->leftchild;
ptr=subL->rightchild ;
subL->rightchild = ptr->leftchild;
ptr->leftchild = subL;
//左旋之后调整平衡因子
if (ptr->bf <= 0) {
subL->bf = 0;
}
else {//说明ptr没有左树
subL->bf = -1;
}
subR->leftchild = ptr->rightchild;
ptr->rightchild = subR;
if (ptr->bf == -1) {//说明ptr有没有右树
subR->bf = 1;
}
else {
subR->bf = 0;
}
ptr->bf = 0;//ptr最后是根节点
}


先右后左双旋
void RotateRL(AVLNode* &ptr) {
AVLNode* subL = ptr;
AVLNode* subR = ptr->rightchild;
ptr = subR->leftchild;
//开始右旋
subR->leftchild = ptr->rightchild;
ptr->rightchild = subR;
if (ptr->bf >= 0)
subR->bf = 0;
else
subR->bf = 1;
//开始左旋
subL->rightchild = ptr->leftchild;
ptr->leftchild = subL;
if (ptr->bf == 1)
subL->bf = -1;
else
subL->bf = 0;
ptr->bf = 0;
}

C语言实现平衡二叉搜索树
这篇博客介绍了如何使用C语言实现平衡二叉树,包括定义结构体、插入结点的过程,以及在插入过程中如何调整平衡因子。通过插入结点的分析,详细阐述了如何设置父结点,并借助栈来维护平衡。当平衡因子不为0时,会进行右单旋、左单旋、先左后右双旋和先右后左双旋等旋转操作,以保持树的平衡。删除结点的策略和旋转函数也进行了说明。
1651

被折叠的 条评论
为什么被折叠?



