C++实现 AVL树

AVL树简介

AVL树是 “ 搜索 平衡 二叉 树” ,我们知道 AVL树 来自 搜索 树, 我们知道 搜素树可以有效的提高数据的查找效率, 但是如果我们创建搜索树时,数据接近有序,搜索树就会退化成单支,此时我们查找的时间复杂度依然会是O(n)。

因此, 俄罗斯的两位数学家发明了AVL树解决了这个问题,AVL树的命名也是由两位数学家的名字缩写得来。

AVL树的特点是, 树中,任意一个节点的左右子树的高度之差不大于1。 这样就避免了搜索树退化成单支的问题。当AVL数有n个节点时, 搜索的复杂度可以始终保持在O(以2为底n的对数)。

AVL树的基本操作

AVL树的节点

AVL树本质上还是一颗搜索二叉树。 我们除了本来的左子树指针,右子树指针,节点值以外,我们还需要保存一个平衡因子,平衡因子用来记录该节点的左右子树高度差,同时为了我们方便操作,额外保存一个指向父节点的节点指针。

template<class K,class V>
class AVLTreeNode {
   
public:
	AVLTreeNode<K, V>* _left;
	AVLTreeNode<K, V>* _right;
	AVLTreeNode<K, V>* _parent;   // 指向父亲
	std::pair<K, V> _kv;
	int _bf;  // 平衡因子   右边高度 减去 左边高度

	AVLTreeNode(const pair<K,V>& kv)
		:_left(nullptr)
		,_right(nullptr)
		,_parent(nullptr)
		,_kv(kv)
		,_bf(0)
	{
   }
};

值得注意的是, 我们不一定需要额外保存平衡因子和父节点指针。如果不记录平衡因子,我们则可以利用栈来保存访问路径,和计算高度。相比之下,额外保存平衡因子和父节点更加方便处理。

搜索

AVL树的搜索和普通的搜索树操作并无区别,通过中序遍历 ,即可得到有序序列。

插入

平衡因子

AVL的基础依旧还是搜索树,所以插入AVL树同样是通过查找到特定位置然后插入。但是在插入后,我们需要更新各个节点的平衡因子。
在这里插入图片描述
例如原本蓝色部分是一颗符合规则的AVL树,当我们新插入一个红色节点时,我们自下往上更新平衡因子。如果一个节点的平衡因子达到-2或者2,此时就说明该节点的左右子树高度已经出现问题需要调整,此时我们就不需要继续向上更新节点的高度了。
那么如果我们新增的节点在父节点的右边, 则父节点的平衡因子++;
如果我们新增的节点在父节点的左边,则父节点的平衡因子–;

跟新玩父节点的平衡因子以后,如果父节点的平衡因子为0,则说明父节点的所在的子树高度不变。(因为能变成0 则说明父节点原来的平衡因子为1或者-1 ,只有将高度较低的一段新增节点后才能变成0),此时我们就可以停止向上对平衡因子的更新。 但如果父节点的更新后为1或者-1, 则说明父节点所在子树的高度变化了(因为父节点的平衡因子变成1或者-1,则说明父节点原来的平衡因子是0,此时我们新增了一个节点让一边的高度增加了。这时我们就需要继续向上更新平衡因子。

右旋

当调整完平衡因子时,有可能会出现不平衡的情况,当新节点插入较高左子树的左侧时。
在这里插入图片描述
例如图中这样的情况,我们就需要进行“右旋”。
在这里插入图片描述

我们将 cur的右子树,移给parent的左子树,然后再将parent 宜给cur的右子树,这样整棵树就会完成调整,然后cur 和parent 的平衡因子都会变为零。

//右旋
void RotateR(Node* parent) {
   
		Node* subL = parent->_left;
		Node* subLR = subL->_right;

		parent->_left = subLR;
		if (subLR != nullptr) {
     //注意调整节点 指向父节点 的指针 指向。
			subLR->_parent = parent;
		}

		Node* parentparent =
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
AVL的插入和删除操作都需要对进行旋转操作来保持AVL的平衡性。下面是C语言实现AVL插入和删除操作: AVL插入操作: ```c // AVL节点定义 struct AVLNode { int key; int height; struct AVLNode* left; struct AVLNode* right; }; // 计算节点高度 int height(struct AVLNode* node) { if (node == NULL) { return 0; } return node->height; } // 右旋操作 struct AVLNode* rotate_right(struct AVLNode* y) { struct AVLNode* x = y->left; struct AVLNode* t2 = x->right; // 执行旋转 x->right = y; y->left = t2; // 更新高度 y->height = max(height(y->left), height(y->right)) + 1; x->height = max(height(x->left), height(x->right)) + 1; return x; } // 左旋操作 struct AVLNode* rotate_left(struct AVLNode* x) { struct AVLNode* y = x->right; struct AVLNode* t2 = y->left; // 执行旋转 y->left = x; x->right = t2; // 更新高度 x->height = max(height(x->left), height(x->right)) + 1; y->height = max(height(y->left), height(y->right)) + 1; return y; } // 计算平衡因子 int balance_factor(struct AVLNode* node) { if (node == NULL) { return 0; } return height(node->left) - height(node->right); } // 插入节点 struct AVLNode* avl_insert(struct AVLNode* node, int key) { // 执行BST插入 if (node == NULL) { struct AVLNode* new_node = (struct AVLNode*)malloc(sizeof(struct AVLNode)); new_node->key = key; new_node->height = 1; new_node->left = NULL; new_node->right = NULL; return new_node; } if (key < node->key) { node->left = avl_insert(node->left, key); } else if (key > node->key) { node->right = avl_insert(node->right, key); } else { // key已经存在,不需要插入 return node; } // 更新高度 node->height = max(height(node->left), height(node->right)) + 1; // 计算平衡因子 int bf = balance_factor(node); // 如果平衡因子大于1,需要进行旋转操作 if (bf > 1) { if (key < node->left->key) { // 左左情况,执行右旋操作 return rotate_right(node); } else { // 左右情况,先对左子进行左旋操作,再对根节点进行右旋操作 node->left = rotate_left(node->left); return rotate_right(node); } } else if (bf < -1) { if (key > node->right->key) { // 右右情况,执行左旋操作 return rotate_left(node); } else { // 右左情况,先对右子进行右旋操作,再对根节点进行左旋操作 node->right = rotate_right(node->right); return rotate_left(node); } } return node; } ``` AVL删除操作: ```c // 查找最小值节点 struct AVLNode* find_min(struct AVLNode* node) { if (node == NULL) { return NULL; } if (node->left == NULL) { return node; } return find_min(node->left); } // 删除节点 struct AVLNode* avl_delete(struct AVLNode* node, int key) { // 执行BST删除 if (node == NULL) { return NULL; } if (key < node->key) { node->left = avl_delete(node->left, key); } else if (key > node->key) { node->right = avl_delete(node->right, key); } else { if (node->left == NULL || node->right == NULL) { // 被删除节点只有一个子节点或者没有子节点 struct AVLNode* temp = node->left ? node->left : node->right; if (temp == NULL) { // 没有子节点,直接删除 temp = node; node = NULL; } else { // 有一个子节点,用子节点替换被删除节点 *node = *temp; } free(temp); } else { // 被删除节点有两个子节点,找到右子的最小值节点替换被删除节点 struct AVLNode* temp = find_min(node->right); node->key = temp->key; node->right = avl_delete(node->right, temp->key); } } if (node == NULL) { return NULL; } // 更新高度 node->height = max(height(node->left), height(node->right)) + 1; // 计算平衡因子 int bf = balance_factor(node); // 如果平衡因子大于1,需要进行旋转操作 if (bf > 1) { if (balance_factor(node->left) >= 0) { // 左左情况,执行右旋操作 return rotate_right(node); } else { // 左右情况,先对左子进行左旋操作,再对根节点进行右旋操作 node->left = rotate_left(node->left); return rotate_right(node); } } else if (bf < -1) { if (balance_factor(node->right) <= 0) { // 右右情况,执行左旋操作 return rotate_left(node); } else { // 右左情况,先对右子进行右旋操作,再对根节点进行左旋操作 node->right = rotate_right(node->right); return rotate_left(node); } } return node; } ``` 以上是AVL的插入和删除操作的C语言实现。需要注意的是,AVL的插入和删除操作都需要对进行旋转操作来保持平衡,因此这些操作的时间复杂度是O(log n)。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值