AVL-Tree是计算机科学中最早被发明的自平衡二叉查找树,在AVL树中,任一节点对应的两棵子树的最大高度差为1,因此它也被称为高度平衡树。查找、插入和删除在平均和最坏情况下的时间复杂度都是O(log n)。增加和删除元素的操作则可能需要借由一次或多次旋转,以实现树的重新平衡。
节点的平衡因子为左子树高度减去右子树高度的绝对值。平衡因子大于1被认为是不平衡的,需要重新平衡。
左旋转:根节点的右节点称为新的根节点,同时,右节点的子节点作为之前根节点的右节点存在。
右旋转:根节点的左节点作为新的根节点,同时,左节点的子节点作为之前根节点的左节点存在。
AVL树的平衡分为4种情况
描述 | 旋转方式 | |
LL | 在根节点的左子树节点的左子树插入节点破坏平衡 | 围绕根节点左子树根节点右旋转 |
LR | 在根节点的左子树节点的右子树插入节点破坏平衡 | 先围绕根节点左子树根节点左旋转,再围绕左子树根节点右旋转 |
RR | 在根节点的右子树节点的右子树插入节点破坏平衡 | 围绕根节点左子树根节点左旋转 |
RL | 在根节点的右子树节点的左子树插入节点破坏平衡 | 先围绕根节点右子树根节点右旋转,再围绕左子树根节点左旋转 |
AVL树的旋转很难理解,这里做个示例,下图是一个有5个节点,高度为2的avl二叉树:
当平衡情况为LL时
经过右旋转结果为
当平衡结果为LR时(在节点左子树的右子树上添加节点),这是通过简单的右旋转无法得到avl树
先绕根节点左子树根节点左旋转,得到
在通过右旋转得到
用gpt写一个avl树的代码,本代码用于查找区间数组中与目标区间有重叠的区间,但并不是解决目标问题的最佳方式,计算时间大于线性搜索,如下
class AVLTree {
public:
AVLTree() : root(nullptr) {}
~AVLTree() { clear(root); }
void insert(Interval interval);
vector<Interval> findIntersectingIntervals(Interval targetInterval);
private:
Node* root;
int height(Node* node);
int balanceFactor(Node* node);
void fixHeight(Node* node);
Node* rotateRight(Node* node);
Node* rotateLeft(Node* node);
Node* balance(Node* node);
Node* insert(Node* node, Interval interval);
void traverse(Node* node, Interval &targetInterval, vector<Interval>& result);
void clear(Node* node);
};
void AVLTree::insert(Interval interval) {
root = insert(root, interval);
}
vector<Interval> AVLTree::findIntersectingIntervals(Interval targetInterval) {
vector<Interval> result;
traverse(root, targetInterval, result);
return result;
}
int AVLTree::height(Node* node) {
return (node == nullptr) ? 0 : node->height;
}
int AVLTree::balanceFactor(Node* node) {
return height(node->left) - height(node->right);
}
void AVLTree::fixHeight(Node* node) {
int heightLeft = height(node->left);
int heightRight = height(node->right);
node->height = max(heightLeft, heightRight) + 1;
}
Node* AVLTree::rotateRight(Node* node) {
Node* newNode = node->left;
node->left = newNode->right;
newNode->right = node;
fixHeight(node);
fixHeight(newNode);
return newNode;
}
Node* AVLTree::rotateLeft(Node* node) {
Node* newNode = node->right;
node->right = newNode->left;
newNode->left = node;
fixHeight(node);
fixHeight(newNode);
return newNode;
}
Node* AVLTree::balance(Node* node) {
fixHeight(node);
int bf = balanceFactor(node);
//balance factor = 2
if (bf == 2) {
if (balanceFactor(node->left) < 0) {
node->left = rotateLeft(node->left); // LR left rotate first
}
return rotateRight(node); //LL right rotate
}
if (bf == -2) {
if (balanceFactor(node->right) > 0) {
node->right = rotateRight(node->right); //RL right rotate first
}
return rotateLeft(node); //RR left rotate
}
return node;
}
Node* AVLTree::insert(Node* node, Interval interval)
{
if (node == nullptr) {
Node* newNode = new Node{ interval, 1, nullptr, nullptr };
return newNode;
}
if (interval.start < node->interval.start) {
node->left = insert(node->left, interval);
}
else
{
node->right = insert(node->right, interval);
}
return balance(node);
}
void AVLTree::traverse(Node* node, Interval &target, vector<Interval>& result) {
Interval interval = node->interval;
if (!(interval.end < target.start || interval.start > target.end))
{
result.push_back(interval);
}
if (node->left) {
traverse(node->left, target, result);
}
if (node->right && (node->interval.start <= target.end)) {
traverse(node->right, target, result);
}
}
void AVLTree::clear(Node* node) {
if (node) {
clear(node->left);
clear(node->right);
delete node;
}
}