对于二叉查找树,当插入节点时,在一些情况下,而二叉树会出现不平衡的状况,即将节点都插入到了二叉树的左子树上;使得二叉树的查找性能大打折扣,因此,为了解决了二叉查找树退化成链表的问题,引入了平衡二叉树。
平衡二叉树(AVL)
定义:
平衡二叉树
1.左、右子树的高度差的绝对值小于等于1;
2.左、右子树也分别为平衡二叉树。
平衡因子-将二叉树上节点的左子树减去右子树高度的值,称为该节点的平衡因子BF。
最小不平衡子树-距离插入节点最近的,且以平衡因子的绝对值大于1的节点为根的子树。
typedef int TreeKeyType; struct AvlNode { TreeKeyType data; int height; //结点所在高度 AvlNode *left; AvlNode> *right; //构造函数 AvlNode(Data) : data(Data), left(NULL), right(NULL), height(0){} };
插入(可能导致失衡,须进行调整):
void Insert(AvlNode *&t, TreeKeyType x) { if (t == NULL) t = new AvlNode(x); //插入到左子树 else if (x < t->data) { Insert(t->left, x); //判断平衡情况,若左子树比右子树高导致不平衡 if (GetHeight(t->left) - GetHeight(t->right) > 1) { if (x < t->left->data) //向左子树插入左孩子导致失衡 RR(t);//右单旋转 else //向左子树插入右孩子导致失衡 LR(t);//先左后右旋转 } } //插入到右子树 else if (x > t->data) { Insert(t->right, x); if (GetHeight(t->right) - GetHeight(t->left) > 1) { if (x > t->right->data) LL(t); elseRL(t); } } //数据重复,不进行插入 else return; //更新树的高度 t->height = max(GetHeight(t->left), GetHeight(t->right)) + 1; }
1、左单旋转
向右子树插入右孩子导致AVL失衡时,需要围绕最小失衡子树的根节点进行左单旋转。
void RR(AvlNode *& t) { AvlNode *q = t->right;//q指向t的右子树的根节点 t->right = q->left;//q的左子树挂为t的右子树 q->left = t;//t变为q的左子树 t = q; t->height = max(GetHeight(t->left), GetHeight(t->right)) + 1; }
2、右单旋转
向左子树插入左孩子导致AVL失衡时,需要围绕最小失衡子树的根节点进行右单旋转。
void LL(AvlNode *& t) { AvlNode *q = t->left; t->left = q->right; q->right = t; t = q; t->height = max(GetHeight(t->left), GetHeight(t->right)) + 1; }
3、先左旋后右旋
在左子树上插入右孩子导致AVL树失衡时,需要进行先左旋后右旋。
LR(AvlNode *& t) { //双旋转可以通过两次单旋转实现 //对t的左结点进行RR旋转,再对根节点进行LL旋转 RR(t->left); LL(t); }
4、先右旋后左旋
在右子树上插入左孩子导致AVL树失衡时,需要进行先右旋后左旋。
void RL(AvlNode *& t) { LL(t->right); RR(t); }
删除
1、删除右子树的节点
删除右子树的节点导致AVL树失衡,相当于在左子树插入新节点导致AVL树失衡,应进行右单旋转或先右旋后左旋。
2、删除左子树的节点
删除左子树的节点导致AVL树失衡,相当于在右子树插入新节点导致AVL树失衡,应进行左单旋转或者先左旋后右旋。
AvlNode * FindMax(AvlNode *t) const { if (t == NULL) return NULL; if (t->right == NULL) return t; return FindMax(t->right); } AvlNode * FindMin(AvlNode *t) const { if (t == NULL) return NULL; if (t->left == NULL) return t; return FindMin(t->left); } int GetHeight(AvlNode *t) { if (t == NULL) return -1; else return t->height; } bool Delete(AvlNode *&t, T x) { //t为空 未找到要删除的结点 if (t == NULL) return false; //找到了要删除的结点 else if (t->data == x) { //左右子树都非空 if (t->left != NULL && t->right != NULL) {//在高度更大的那个子树上进行删除操作 //左子树高度大,删除左子树中值最大的结点,将其赋给根结点 if (GetHeight(t->left) > GetHeight(t->right)) { t->data = FindMax(t->left)->data; Delete(t->left, t->data); } else//右子树高度更大,删除右子树中值最小的结点,将其赋给根结点 { t->data = FindMin(t->right)->data; Delete(t->right, t->data); } } else {//左右子树有一个不为空,直接用需要删除的结点的子结点替换即可 AvlNode *old = t; t = t->left ? t->left: t->right;//t赋值为不空的子结点 delete old; } } else if (x < t->data)//要删除的结点在左子树上 { //递归删除左子树上的结点 Delete(t->left, x); //判断是否仍然满足平衡条件 if (GetHeight(t->right) - GetHeight(t->left) > 1) { if (GetHeight(t->right->left) > GetHeight(t->right->right)) { //RL双旋转 t = RL(t); } else {//RR单旋转 t = RR(t); } } else//满足平衡条件 调整高度信息 { t->height = max(GetHeight(t->left), GetHeight(t->right)) + 1; } } else//要删除的结点在右子树上 { //递归删除右子树结点 Delete(t->right, x); //判断平衡情况 if (GetHeight(t->left) - GetHeight(t->right) > 1) { if (GetHeight(t->left->right) > GetHeight(t->left->left)) { //LR双旋转 t = LR(t); } else { //LL单旋转 t = LL(t); } } else//满足平衡性 调整高度 { t->height = max(GetHeight(t->left), GetHeight(t->right)) + 1; } } return true; }
查找和遍历同二叉查找树