红黑树的基础——AVL树

AVL树

特点:
前提:是一棵二叉搜索树
左右子树高度之差(简称为平衡因子)的绝对值不超过1
左右子树也是一颗AVL树

AVL树避免了一般二叉搜索树会出现单边树的情况

代码定义

template<class T>
//定义节点
struct AVLNode {
	T _val;
	int _bf;//平衡因子
	AVLNode<T>* _left;
	AVLNode<T>* _right;
	AVLNode<T>* _parent;

	AVLNode(const T& val = T())
		:_val(val)
		,bf(0)
		,_left(nullptr)
		,_right(nullptr)
		,_parent(nullptr)
	{}
};

template<class T>
//定义AVL树
class AVLTree {
public:
	typedef AVLNode<T> Node;
	AVLTree()
		:_root(nullptr)
	{}
    bool insert(const T& val);
    //右旋操作
    void RotateR(Node* parent);
    //左旋操作
    void RotateL(Node* parent);

    //中序遍历
	void inorder() {
		_inorder(_root);
		cout << endl;
	}
	void _inorder(Node* root) {
		if (root) {
			_inorder(root->_left);
			cout << root->_val << " ";
			_inorder(root->_right);
		}
	}
	
	//检查是否是AVL树
	bool isAVLTree() {
		return _isAVLTree(_root);
	}
	bool _isAVLTree(Node* root) {
		if (root == nullptr) {
			return true;
	    }
	    int subL = Height(root->_left);
		int subR = Height(root->_right);
		if (root->_bf != subR - subL) {
			cout << "节点:" << root->_val << "异常:bf:" << root->_bf << "高度差:" << subR - subL << endl;
			return false;
		}
		return abs(root->_bf) < 2 && _isAVLTree(root->_left) && _isAVLTree(root->_right);
	}

    //记录以root为根的树的高度
	int Height(Node* root) {
		if (root == nullptr) {
			return 0;
		}
		int left = Height(root->_left);
		int right = Height(root->_right);
		return left > right ? left + 1 : right + 1;
	}
private:
	Node* _root;
};

AVL树的插入

在这里插入图片描述
如上如图,在图中插入值为10的结点之后,二叉搜索树会不满足AVL树的条件,需要对树进行调整
调整之后为
在这里插入图片描述
有可能更新平衡因子的节点:
1.新插入的节点的所有祖先节点,如果其高度发生了变化,则需要更新
2.如果一个节点的子树高度发生了变化,则需要更新

调整树的结构
当一棵二叉搜索树中的平衡因子出现2或者-2时,那么这棵树就要进行相应的调整才能变成AVL树
右旋:左边的左边高,如下图
在这里插入图片描述在这里插入图片描述
左旋:右边的右边高,如下图
在这里插入图片描述
在这里插入图片描述
右左双旋:右边的左边高,如下图
在这里插入图片描述
左右双旋:左边的右边高,如下图
在这里插入图片描述
代码实现

bool insert(const T& val) {
    //插入基本操作同二叉搜索树的插入
	if (_root == nullptr) {
		_root =new Node(val);
		return true;
	}
	Node* cur = _root;
	Node* parent = nullptr;
	while (cur) {
		parent = cur;
		if (cur->_val == val) {
			return false;
		}
		else if (cur->_val > val) {
			cur = cur->_left;
		}
		else {
			cur = cur->_right;
		}
	}
	cur = new Node(val);
	if (parent->_val > val) {
		parent->_left = cur;
	}
	else {
		parent->_right = cur;
	}
	cur->_parent = parent;

    //更新平衡因子,调整树的结构
	while (parent) {
		//更新parent的平衡因子
		if (parent->_left == cur) {
			parent->_bf--;
		}
		else {
			parent->_bf++;
		}
		//判断是否需要继续向上更新
		if (parent->_bf == 0) {
		//节点平衡因子更新为0,则表示对于它的祖先节点来说,它本身的高度不影响祖先节点的高度
			break;
		}
		else if (parent->_bf == 1 || parent->_bf == -1) {
			//继续向上更新
			cur = parent;
			parent = parent->_parent;
		}
		else if (parent->_bf == -2 || parent->_bf == 2) {
			//需要调整树的结构
			if (parent->_bf == -2 && cur->_bf == -1) {
				//左边的左边高,右旋
				RotateR(parent);
				cout << "insert: " << val << "右旋:" << parent->_val << endl;
			}
			else if (parent->_bf == 2 && cur->_bf == 1) {
				//右边的右边高,左旋
				RotateL(parent);
				cout << "insert: " << val << "左旋:" << parent->_val << endl;
			}
			else if (parent->_bf == 2 && cur->_bf == -1) {
				//右边的左边高
				cout << "insert: " << val << "右左双旋" << parent->_val << " " << cur->_val << endl;
				Node* subR = parent->_right;
				Node* subRL = subR->_left;
				int bf = subRL->_bf;
				//先以cur为轴右旋
				RotateR(cur);
				//再以parent为轴左旋
				RotateL(parent);

                //调整平衡因子
				if (bf == 1) {
					//subRL的右子树高
					subR->_bf = 0;
					parent->_bf = -1;
				}
				else if (bf == -1) {
					//subRL的左子树高
					subR->_bf = 1;
					parent->_bf = 0;
				}
			}
			else if (parent->_bf == -2 && cur->_bf == 1) {
				//左边的右边高
				cout << "insert: " << val << "左右双旋" << parent->_val << " " << cur->_val << endl;
				Node* subL = parent->_left;
				Node* subLR = subR->_right;
				int bf = subLR->_bf;
				//先以cur为轴左旋
				RotateL(cur);
				//再以parent为轴右旋
				RotateR(parent);

                //调整平衡因子
				if (bf == -1) {
					//subLR的左子树高
					subL->_bf = 0;
					parent->_bf = 1;
				}
				else if (bf == 1) {
					//subLR的右子树高
					subL->_bf = -1;
					parent->_bf = 0;
				}
			}
			break;
		}
	}
	return true;
}

//右旋操作
void RotateR(Node* parent) {
	Node* subL = parent->_left;
	Node* subLR = subL->_right;
    //更新subL、subLR、parent以及parent->_parent,四个节点之间的六个连接
	subL->_right = parent;
	parent->_left = subLR;

    if (subLR) {
		subLR->_parent = parent;
	}
	
	//没有parent->_parent的情况
	if (parent == _root) {
		_root = subL;
		subL->_parent = nullptr;
	}
	
	//有parent->_parent的情况
	else {
		Node* pp = parent->_parent;
		subL->_parent = pp;
		if (pp->_left == parent) {
			pp->_left = subL;
		}
		else {
			pp->_right = subL;
		}
	}
	parent->_parent = subL;
	parent->_bf = subL->_bf = 0;
}

//左旋操作
void RotateL(Node* parent) {
	Node* subR = parent->_right;
	Node* subRL = subR->_left;

    //更新subR、subRL、parent以及parent->_parent,四个节点之间的六个连接
	subR->_left = parent;
	parent->_right = subRL;

    if (subRL) {
		subRL->_parent = parent;
	}

    //没有parent->_parent的情况
	if (parent == _root) {
		_root = subR;
		subR->_parent = nullptr;
	}
	
	//有parent->_parent的情况
	else {
		Node* pp = parent->_parent;
		subR->_parent = pp;
		if (pp->_left == parent) {
			pp->_left = subR;
		}
		else {
			pp->_right = subR;
		}
	}
	parent->_parent = subR;
	parent->_bf = subR->_bf = 0;
}

总结
AVL树的插入操作
1.二叉搜索树的插入
2.从新插入节点对应的父亲节点开始更新平衡因子
3.在2中,平衡因子更新完成后
A.平衡因子:0 >>停止向上更新
B.平衡因子:1或者-1 >> 继续向上更新
C.平衡因子:2或者-2 >> 旋转树的结构
a.左旋:右边的右边高,parent->bf == 2,cur->bf == 1
b.右旋:左边的左边高,parent->bf == -2,cur->bf == -1
c.右左双旋:右边的左边高,parent->bf == 2,cur->bf == -1
d.左右双旋:左边的右边高,parent->bf == -2,cur->bf == 1

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值