AVL树的插入和删除

来源:互联网 发布:node sass失败 编辑:程序博客网 时间:2024/06/05 18:15

1. 概述

AVL树是最早提出的自平衡二叉树,在AVL树中任何节点的两个子树的高度最大差别为一,所以它也被称为高度平衡树。AVL树得名于它的发明者G.M. Adelson-Velsky和E.M. Landis。AVL树种查找、插入和删除在平均和最坏情况下都是O(log n),增加和删除可能需要通过一次或多次树旋转来重新平衡这个树。本文介绍了AVL树的设计思想和基本操作。

2. 基本术语

有四种种情况可能导致二叉查找树不平衡,分别为:

(1)LL:插入一个新节点到根节点的左子树(Left)的左子树(Left),导致根节点的平衡因子由1变为2

(2)RR:插入一个新节点到根节点的右子树(Right)的右子树(Right),导致根节点的平衡因子由-1变为-2

(3)LR:插入一个新节点到根节点的左子树(Left)的右子树(Right),导致根节点的平衡因子由1变为2

(4)RL:插入一个新节点到根节点的右子树(Right)的左子树(Left),导致根节点的平衡因子由-1变为-2

针对四种种情况可能导致的不平衡,可以通过旋转使之变平衡。有两种基本的旋转:

(1)左旋转:将根节点旋转到(根节点的)右孩子的左孩子位置

(2)右旋转:将根节点旋转到(根节点的)左孩子的右孩子位置

3. AVL树的旋转操作

AVL树的基本操作是旋转,有四种旋转方式,分别为:左旋转,右旋转,左右旋转(先左后右),右左旋转(先右后左),实际上,这四种旋转操作两两对称,因而也可以说成两类旋转操作。

3.1 LL

LL情况需要右旋解决,如下图所示:

右旋部分代码如下:

BiTree SingleRight(BiTree k1)//单旋:右旋{    BiTree k2;    k2 = k1->lchild;    k1->lchild = k2->rchild;    k2->rchild = k1;    k1->height = MAX(Height(k1->lchild), Height(k1->rchild));    k2->height = MAX(Height(k2->lchild), Height(k1));    return k2;}
这是没有删除的代码,没有父母节点,看起来简单些,不要过多考虑边界

3.2 RR

RR情况需要左旋解决,如下图所示:

左旋部分代码如下:

BiTree SingleLeft(BiTree k1)//单旋:左旋{BiTree k2;k2 = k1->rchild;k1->rchild = k2->lchild;k2->lchild = k1;k1->height = MAX(Height(k1->lchild), Height(k1->rchild));k2->height = MAX(Height(k2->rchild), Height(k1));return k2;}

3.3 LR

LR情况需要左右(先B左旋转,后A右旋转)旋解决,如下图所示:

BiTree LeftRight(BiTree k1){k1->lchild = SingleLeft(k1->lchild);return SingleRight(k1);}

3.4 RL

RL情况需要右左旋解决(先B右旋转,后A左旋转),如下图所示:

BiTree RightLeft(BiTree k1)//双旋: 右左(从下往上  右旋-左旋){k1->rchild = SingleRight(k1->rchild);//右旋return SingleLeft(k1);//左旋}

4. AVL数的插入和删除操作

(1) 插入操作:实际上就是在不同情况下采用不同的旋转方式调整整棵树

  在查找二叉树的插入的通识判断是否出现了不平衡,若是不平衡,则根据以上4中情况做相应的调整

(2) 删除操作:首先定位要删除的节点,将该节点删除(与查找二叉树一般)

然后沿着被删除的节点自下而上的调整树到根节点(需要回溯,所以要引入父母节点)

Note:

!!!由于引入了父母节点,所以在操作的时候,旋转,删除,插入都需要注意对父母节点的变化做处理

!!!!有着更为简便的删除------懒惰删除


附完整代码如下:

#include <stdio.h>#include <malloc.h>#include <stdlib.h>#include <string.h>typedef struct tree{char data;int hight;int bf;//平衡因子:左树高度减去右树高度struct tree *lchild;struct tree *rchild;struct tree *parent;//删除所用,指向父母}Node, *Tree;void Init(Tree *T, char data)//初始化根节点:父母为NULL{*T = (Tree)malloc(sizeof(Node));(*T)->data = data;(*T)->hight = 1;(*T)->bf = 0;(*T)->parent = (*T)->lchild = (*T)->rchild = NULL;}int MAX(int a, int b){if (a > b)return a + 1;return b + 1;}int Height(Tree T)//返回高度{if (T)return T->hight;return -1;}Tree SingleLeft(Tree k1)//单旋:左旋  注意父母的变化{//引入如父母这一指针,所以需要注意在旋转的时候,需要将父母也变换Tree k2 = k1->rchild;k1->rchild = k2->lchild;if (k2->lchild)k2->lchild->parent = k1;k2->lchild = k1;k2->parent = k1->parent;//注意这二者的顺序,若是相反,则会有k2->parent = k2;k1->parent = k2;k1->hight = MAX(Height(k1->lchild), Height(k1->rchild));k2->hight = MAX(Height(k2->lchild), Height(k2->rchild));k1->bf = Height(k1->lchild) - Height(k1->rchild);k2->bf = Height(k2->lchild) - Height(k2->rchild);return k2;}Tree SingleRight(Tree k1)//单旋:右旋{Tree k2 = k1->lchild;k1->lchild = k2->rchild;if (k2->rchild)k2->rchild->parent = k1;k2->rchild = k1;k2->parent = k1->parent;k1->parent = k2;k1->hight = MAX(Height(k1->lchild), Height(k1->rchild));k2->hight = MAX(Height(k2->lchild), Height(k2->rchild));k1->bf = Height(k1->lchild) - Height(k1->rchild);k2->bf = Height(k2->lchild) - Height(k2->rchild);return k2;}Tree LeftRight(Tree k1)//双旋:左旋——右旋{k1->lchild = SingleLeft(k1->lchild);return SingleRight(k1);}Tree RightLeft(Tree k1)//双旋: 右旋--左旋{k1->rchild = SingleRight(k1->rchild);return SingleLeft(k1);}Tree FindMin(Tree T)//找出最小节点{//错误写法如下:这样会造成对原本数据的改变,我们要做的只是找到最小的元素而已/*while (T->lchild)T = T->lchild;return T;*/Tree temp = T;while (temp->lchild)temp = temp->lchild;return temp;}Tree Insert(Tree T, Tree pre, char data)//插入,边插入边旋转调整平衡   四种对应关系{//由于有parent,所以需要引入pre指向前驱指针if (!T){T = (Tree)malloc(sizeof(Node));if (!T){printf("Can Not Init");return NULL;}T->hight = 1;T->bf = 0;T->data = data;T->parent = pre;T->lchild = T->rchild = NULL;}else {if (T->data < data){T->rchild = Insert(T->rchild, T, data);if (T->bf == -2){if (data < T->rchild->data)//RLT = RightLeft(T);else if (data > T->rchild->data)//RRT = SingleLeft(T);}}if (T->data > data){T->lchild = Insert(T->lchild, T, data);if (T->bf == 2){if (data < T->lchild->data)//LLT = SingleRight(T);else if (data > T->lchild->data)//LRT = LeftRight(T);}}}T->hight = MAX(Height(T->lchild), Height(T->rchild));//高度和平衡因子的更新T->bf = Height(T->lchild) - Height(T->rchild);return T;}Tree Delete(Tree T, char data)//删除操作,比较复杂{  //先按照一般的查找二叉树将节点删除后,再由该节点自下而上的回溯,调整每个节点到平衡至根节点Tree temp, target = T, parent = NULL, grand;char ele;while (target)//删除操作{if (target->data < data)target = target->rchild;else if (target->data > data)target = target->lchild;else if (target->lchild && target->rchild)//找出删除节点{//两个孩子情况temp = FindMin(target->rchild);parent = temp->parent;//注意该语句的顺序,若是对target做了处理且target就是temp的父母,那么此时parent并不准确target->data = temp->data;//if (temp->rchild)//最小节点必然没有左子树//判断删除节点是其父母的左(右)子树,分别处理;if (temp->parent->data <= temp->data)//右子树:注意等号,由于此时temp->parent可能正是target,故可能等于{temp->parent->rchild = temp->rchild;if (temp->rchild)//注意指针父母的变化temp->rchild->parent = temp->parent;}else //左子树{temp->parent->lchild = temp->rchild;if (temp->rchild)temp->rchild->parent = temp->parent;}free(temp);break;}else//只有一个孩子或者没有孩子(树叶) {temp = target;parent = temp->parent;if (target->lchild)//有左孩子if (parent->data < data)//判断删除节点位置在父母节点的左还是右{parent->rchild = target->lchild;target->lchild->parent = parent;}else {parent->lchild = target->lchild;target->lchild->parent = parent;}else //不用判断右孩子是否为空:若是为空,就是孩子,此时等于target->rchild也就是等于NULLif (parent->data < data){parent->rchild = target->rchild;if (target->rchild)target->rchild->parent = parent;}else {parent->lchild = target->rchild;if (target->rchild)target->rchild->parent = parent;}free(temp);break;}}while (parent)//由删除节点往上调整平衡{ele = parent->data;parent->hight = MAX(Height(parent->lchild), Height(parent->rchild));//更新高度和平衡因子parent->bf = Height(parent->lchild) - Height(parent->rchild);grand = parent->parent;if (parent->bf == -2)//四种对应情况,相对于插入来说,有着特殊情况,即bf==0的情况{if (parent->rchild->bf > 0){parent = RightLeft(parent);}else {parent = SingleLeft(parent);}}else if (parent->bf == 2){if (parent->lchild->bf < 0)parent = LeftRight(parent);else parent = SingleRight(parent);}if (grand)//祖父母:这是必须的,否则无法连接{if (grand->data > ele)//判断位置grand->lchild = parent;else grand->rchild = parent;parent->parent = grand;}elseT = parent;//注意:此时说明已经到了根节点,需要变化parent = parent->parent;//往上走}return T;}int main(){Tree T;int i;char *s="ckbfjlaegmdh";Init(&T,'i');for (i = 0; i < strlen(s); i++)T = Insert(T, T, s[i]);T = Delete(T, 'a');//T = Delete(T, 'a');//T = Delete(T, 'j');//T = Delete(T, 'b');//T = Delete(T, 'b');return 0;}

以下是没有删除的代码,没有父母节点,看起来简单些,不要过多考虑边界。

/* * AVL树 :每个节点的左子树和右子树的高度相差至多为1 * :左旋   root旋转到root->right->left * : 右旋   root旋转到root->left->right *  * 左左:  右旋 * 右右:  左旋 * 右左:  先右旋再左旋  (从下往上) * 左右:  先左旋再右旋*/#include <stdio.h>#include <malloc.h>#include <string.h>#include <stdlib.h>#define MAX(a, b) ((((a) > (b)) ? (a) : (b)) + 1)typedef struct tree{int data; int height;struct tree *lchild; struct tree *rchild;}BiNode, *BiTree;void Inisit(BiTree *T, int c){*T = (BiTree)malloc(sizeof(BiNode));(*T)->data = c;(*T)->rchild = (*T)->lchild = NULL;}int Height(BiTree T)//返回树的高度, 树为空的时候返回-1{if (T)return T->height;return -1;}BiTree SingleLeft(BiTree k1)//单旋:左旋{BiTree k2;k2 = k1->rchild;k1->rchild = k2->lchild;k2->lchild = k1;k1->height = MAX(Height(k1->lchild), Height(k1->rchild));k2->height = MAX(Height(k2->rchild), Height(k1));return k2;}BiTree SingleRight(BiTree k1)//单旋: 右旋{BiTree k2;k2 = k1->lchild;k1->lchild = k2->rchild;k2->rchild = k1;k1->height = MAX(Height(k1->lchild), Height(k1->rchild));k2->height = MAX(Height(k2->lchild), Height(k1));return k2;}BiTree RightLeft(BiTree k1)//双旋: 右左(从下往上  右旋-左旋){k1->rchild = SingleRight(k1->rchild);//右旋return SingleLeft(k1);//左旋}BiTree LeftRight(BiTree k1){k1->lchild = SingleLeft(k1->lchild);return SingleRight(k1);}BiTree Insert(BiTree T, int c){if (!T){T = (BiTree)malloc(sizeof(BiNode));if (!T){printf("ERROR");return NULL;}T->lchild = T->rchild = NULL;T->data = c;}if (c > T->data)//Right{T->rchild = Insert(T->rchild, c);if (Height(T->rchild) - Height(T->lchild) == 2)if (c > T->rchild->data)//Right-RightT = SingleLeft(T);elseT = RightLeft(T);//Right-Left}else if (c < T->data) {T->lchild = Insert(T->lchild, c);if (Height(T->lchild) - Height(T->rchild) == 2)if (c < T->lchild->data)//Left-Left//T = SingleRight(T->lchild->data)T = SingleRight(T);else T = LeftRight(T);//Left-Right}T->height = MAX(Height(T->lchild), Height(T->rchild));//对高度做调整return T;}int main(){BiTree T;int i;int s[]={2, 6, 1, 3, 5, 7, 16, 15, 14, 13, 12, 11, 8, 9, 10};Inisit(&T, 4);for (i = 0; i < 15; i++)T = Insert(T, s[i]);return 0;}


原创粉丝点击