搜索结构:AVL树

AVL树是一种高度平衡的二叉搜索树,确保搜索效率维持在O(log2n)。节点的平衡因子是左右子树高度差,保持在-1, 0, 1之间。当插入节点导致不平衡时,通过左单旋、右单旋、先左后右双旋和先右后左双旋四种旋转方式恢复平衡。本文详细介绍了这些旋转操作的图解和代码实现。" 133408104,19990984,CSS实现文字水平排列的技巧,"['前端开发', 'CSS']
摘要由CSDN通过智能技术生成

AVL树

定义

一棵 AVL 树或者是空树,或者是具有下列性质的二叉搜索树:它的左子树和右子树都是 AVL 树,且左子树和右子树的高度之差的绝对值不超过1
在这里插入图片描述

节点的平衡因子

每个结点附加一个数字,给出该结点右子树的高度减去左子树的高度所得的高度差,这个数字即为结点的平衡因子 b f bf bf
AVL树任一结点平衡因子只能取 -1, 0, 1。
如果一个结点的平衡因子的绝对值大于1,则这棵二叉搜索树就失去了平衡,不再是AVL树。
如果一棵有 n 个结点的二叉搜索树是高度平衡的,其高度可保持在 O ( l o g 2 n ) O(log_2n) O(log2n),平均搜索长度也可保持在 O ( l o g 2 n ) O(log_2n) O(log2n)

AVL树的类定义

#include <iostream>
#include “stack.h”
#include <stdlib.h>
template <class E, class K>
struct BSTNode  {			    //二叉树结点类
    E data;				    //数据域
    BSTNode<E, K> *left, *right;  //左子女和右子女
    BSTNode() { left = NULL; right = NULL; }
       //构造函数
    BSTNode (const E d, BSTNode<E, K> *L = NULL, BSTNode<E, K> *R = NULL)
        { data = d; left = L; right = R;}
      //构造函数
    ~BSTNode() {}				//析构函数
    void setData (E d) { data = d; }	//修改	
    E getData() { return data; }		//提取
    bool operator < (const E& x) 	//重载:判小于
        { return data.key < x.key; }   
    bool operator > (const E& x) 	//重载:判大于
        { return data.key > x.key; }
    bool operator == (const E& x) 	//重载:判等于
        { return data.key == x.key; }
};

template <class E, class K>
struct AVLNode : public BSTNode<E, K> {
//AVL树结点的类定义  
    int bf;
	AVLNode() { left = NULL; right = NULL; bf = 0; }
    AVLNode (E d, AVLNode<E, K> *l = NULL,  AVLNode<E, K> *r = NULL) 
        { data = d;  left = l;  right = r;  bf = 0; }
};
template <class E, class K>
class AVLTree : public BST<E, K> {
//平衡的二叉搜索树(AVL)类定义
public:
    AVLTree() { root = NULL; }		//构造函数
    AVLTree (K Ref) { RefValue = Ref; root = NULL; }
    	//构造函数:构造非空AVL树
    int Height() const; 				         //高度
    AVLNode<E, K>* Search (K x, AVLNode<E, K> *& par) const;//搜索
    bool Insert (E& e1) { return Insert (root, e1); } //插入
    bool Remove (K x, E& e1){ return Remove (root, x, e1); }  //删除
    friend istream& operator >> (istream& in, AVLTree<E, K>& Tree);
    	//重载:输入
    friend ostream& operator << (ostream& out,const AVLTree<E, K>& Tree);
    	//重载:输出
protected:
    int Height (AVLNode<E, K> *ptr) const; 
    bool Insert (AVLNode<E, K>*& ptr, E& e1);
    bool Remove (AVLNode<E, K>*& ptr, K x, E& e1);
    void RotateL (AVLNode<E, K>*& ptr); //左单旋
    void RotateR (AVLNode<E, K>*& ptr);	//右单旋
    void RotateLR (AVLNode<E, K>*& ptr);//先左后右双旋
    void RotateRL (AVLNode<E, K>*& ptr);//先右后左双旋
};

平衡化旋转

如果在一棵平衡的二叉搜索树中插入一个新结点,造成了不平衡。此时必须调整树的结构,使之平衡化。
平衡化旋转有两类:
单旋转 (左旋和右旋)
双旋转 (左平衡和右平衡)

每插入一个新结点时, AVL 树中相关结点的平衡状态会发生改变。因此, 在插入一 个新结点后,需要从插入位置沿通向根的路径回溯,检查各结点的平衡因子。如果在某一结点发现高度不平衡,停止回溯。从发生不平衡的结点起,沿刚才回溯的路径取直接下两层的结点。
如果这三个结点处于一条直线上,则采用单旋转进行平衡化。单旋转可按其方向分为左单旋转和右单旋转, 其中一个是另一 个的镜像,其方向与不平衡的形状相关。
如果这三个结点处于一条折线上,则采用双旋转进行平衡化。双旋转分为先左后右和先右后左两类。
在这里插入图片描述

左单旋转

在结点A的右子女的右子树E中插入新结点,该子树高度增1导致结点A的平衡因子变成2,出现不平衡。为使树恢复平衡,从A沿插入路径连续取3个结点A、C和E,以结点C为旋转轴,让结点A反时针旋转。

图解

在这里插入图片描述

代码实现
template <class E, class K> 
void AVLTree<E, K>::RotateL (AVLNode<E, K> *& ptr) {
//右子树比左子树高: 做左单旋转后新根在ptr
    AVLNode<E, K> *subL = ptr;
    ptr = subL->right;
    subL->right = ptr->left;
    ptr->left = subL; 
	ptr->bf = subL->bf = 0;
};

右单旋转

在结点A的左子女的左子树D上插入新结点使其高度增1导致结点A的平衡因子增到-2,造成不平衡。为使树恢复平衡,从A沿插入路径插入路径连续取3 个结点A、B和D,以结点B为旋转轴,将结点A顺时针旋转。

图解

在这里插入图片描述

代码实现
template <class E, class K>
void AVLTree<E, K>::
RotateR (AVLNode<E, K> *& ptr) { 
//左子树比右子树高, 旋转后新根在ptr
    AVLNode<E, K> *subR = ptr;   //要右旋转的结点
    ptr = subR->left;
    subR->left = ptr->right;	      //转移ptr右边负载
    ptr->right = subR;		      //ptr成为新根
    ptr->bf = subR->bf = 0;
};

先左后右双旋转

在结点A的左子女的右子树中插入新结点,该子树高度增1导致结点A的平衡因子变为-2,造成不平衡。

图解

以结点E为旋转轴,将结点B反时针旋转,以E代替原来B的位置。
在这里插入图片描述
再以结点E为旋转轴,将结点A顺时针旋转。使之平衡化
在这里插入图片描述

代码实现
template <class E, class K>
void AVLTree<E, K>:: RotateLR (AVLNode<E, K> *& ptr) {//ptr为要旋转的节点
    AVLNode<E, K> *subR = ptr;//结束时的右子树就是要旋转的ptr
    AVLNode<E, K> *subL = subR->left;//结束时的左子树就是开始时ptr的左子树
    //先左单旋转
    ptr = subL->right;//直接将目标节点翻到根节点的位置
    subL->right = ptr->left;
    ptr->left = subL;
    if (ptr->bf <= 0) subL->bf = 0;//调整平衡因子
    else subL->bf = -1;
    //再右单旋转
    subR->left = ptr->right;
    ptr->right = subR;	
    if (ptr->bf == -1) subR->bf = 1;//调整平衡因子
    else subR->bf = 0;
    ptr->bf = 0;
};

先右后左双旋转

在结点A的右子女的左子树中插入新结点,该子树高度增1。结点A的平衡因子变为2,发生了不平衡。

图解

首先以结点D为旋转轴,将结点C顺时针旋转,以D代替原来C的位置。
在这里插入图片描述
再以结点D为旋转轴,将结点A反时针旋转, 恢复树的平衡。
在这里插入图片描述

代码实现
template <class E, class K>
void AVLTree<E, K>::
RotateRL (AVLNode<E, K> *& ptr) {
    AVLNode<E, K> *subL = ptr;
    AVLNode<E, K> *subR = subL->right;
    //先右单旋转
    ptr = subR->left;
    subR->left = ptr->right; 
    ptr->right = subR;
    if (ptr->bf >= 0) subR->bf = 0;
    else subR->bf = 1;
    //再左单旋转
    subL->right = ptr->left;
    ptr->left = subL;
    if (ptr->bf == 1) subL->bf = -1;
    else subL->bf = 0;
    ptr->bf = 0;
}; 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值