chapter_tree/avl_tree/ #85
Replies: 83 comments 109 replies
-
这部分确实是有点难度 |
Beta Was this translation helpful? Give feedback.
-
K神有时间可以更新一章红黑树的区别吗?想看看它们的区别和各自的应用场景,感谢! |
Beta Was this translation helpful? Give feedback.
-
您好,请问python的会更新吗 |
Beta Was this translation helpful? Give feedback.
-
K神会更新图数据结构嘛 ? |
Beta Was this translation helpful? Give feedback.
-
大佬,请问这一节中哪些函数归在private,哪些函数归在public中,这方面有什么考量吗?比如为什么要将 height 函数和 updateHeight 函数 分别放在 public 和 private 中呢? |
Beta Was this translation helpful? Give feedback.
-
有个疑问,我看右旋操作是处理失衡节点node、child、grandchild之间的关系,那node的父级和node原来的连接不需要维护吗?右旋操作后岂不是断掉了? |
Beta Was this translation helpful? Give feedback.
-
k神,这部分还会介绍红黑树吗? |
Beta Was this translation helpful? Give feedback.
-
大佬,想问一下,updateHeight()方法里为啥要 + 1 操作? |
Beta Was this translation helpful? Give feedback.
-
/* 右旋操作 */ |
Beta Was this translation helpful? Give feedback.
-
讲的不错,经过你的讲解感觉AVL树只有红黑树10%的难度 |
Beta Was this translation helpful? Give feedback.
-
复刻了一下 感觉可以的 |
Beta Was this translation helpful? Give feedback.
-
大佬,先左旋再右旋那张图,child.left=node, node.left=null也可以达到平衡吧,只是破坏了二叉搜索树的规则,这种做法属于左旋吗?左旋的时候child既可以取node左子节点也可以取右子节点吧,右旋同理 |
Beta Was this translation helpful? Give feedback.
-
if t.balanceFactor(node.Left) >= 0 { 为什么判断条件是 >= 0,是不是 > 0 也可以,因为左右高度差不可能为 0 |
Beta Was this translation helpful? Give feedback.
-
为什么不用 updateHeight(grandChild) 呀? |
Beta Was this translation helpful? Give feedback.
-
这里讲的真好,清楚易懂 |
Beta Was this translation helpful? Give feedback.
-
文章已经写的很清晰了,但是没有动图, 看了这篇文章更好理解 🫡 |
Beta Was this translation helpful? Give feedback.
-
我想知道这个应该学到什么程度才算掌握啊,是不是要能凭借自己可以全敲出来才算掌握,然后在去学下一个结构啊 |
Beta Was this translation helpful? Give feedback.
-
这个左旋右旋操作结束后,原本指向node的pre会直接指向操作后的child吗?是操作少了一步还是我的理解有问题 |
Beta Was this translation helpful? Give feedback.
-
手搓翻转红黑 |
Beta Was this translation helpful? Give feedback.
-
//我一个一个右鞭腿,一个左正蹬
// 左旋操作
|
Beta Was this translation helpful? Give feedback.
-
这个树是要每次增减都进行维护才能保持平衡吗?
就会死循环吧 |
Beta Was this translation helpful? Give feedback.
-
我看完了,, 但感觉好难实现啊, 我准备实现以下,,, |
Beta Was this translation helpful? Give feedback.
-
day07 |
Beta Was this translation helpful? Give feedback.
-
先左旋后右旋的例子中如果 1 节点的左边有一个 0 的节点该怎么旋转? |
Beta Was this translation helpful? Give feedback.
-
失衡的节点旋转完成后,对于原先失衡的父节点来说这个操作应该是不可知的,他指向的还是失衡的节点。所以在main函数里面进行平衡的时候的代码是 root->right = rotate(root->right); 这样吗 |
Beta Was this translation helpful? Give feedback.
-
旋转的核心在于爸爸变儿子 |
Beta Was this translation helpful? Give feedback.
-
写一个 // AVL树节点结构
template<typename T>
struct AVLNode {
T key;
AVLNode* left;
AVLNode* right;
int height; // 节点高度
AVLNode(T value) : key(value), left(nullptr), right(nullptr), height(1) {}
};
template<typename T>
class AVLTree {
private:
AVLNode<T>* root;
// 获取节点高度
int height(AVLNode<T>* node) {
return node ? node->height : 0;
}
// 获取平衡因子(左子树高度 - 右子树高度)
int getBalance(AVLNode<T>* node) {
return node ? height(node->left) - height(node->right) : 0;
}
/*
初始状态:
y
/ \
x γ
/ \
α T2
右旋后:
x
/ \
α y
/ \
T2 γ
*/
// 右旋操作
AVLNode<T>* rightRotate(AVLNode<T>* y) {
AVLNode<T>* x = y->left;
AVLNode<T>* 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; // 返回新的根节点
}
/*
初始状态:
x
/ \
α y
/ \
T2 β
左旋后:
y
/ \
x β
/ \
α T2
*/
// 左旋操作
AVLNode<T>* leftRotate(AVLNode<T>* x) {
AVLNode<T>* y = x->right;
AVLNode<T>* 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; // 返回新的根节点
}
// 插入节点(递归辅助函数)
AVLNode<T>* insert(AVLNode<T>* node, T key) {
// 1. 执行标准BST插入
if (node == nullptr)
return new AVLNode<T>(key);
if (key < node->key)
node->left = insert(node->left, key);
else if (key > node->key)
node->right = insert(node->right, key);
else // 不允许重复键
return node;
// 2. 修复平衡
return fixBalance(node);
}
// 删除节点(递归辅助函数)
AVLNode<T>* remove(AVLNode<T>* node, T key) {
// 1. 执行标准BST删除
if (node == nullptr)
return node;
// 递归查找要删除的节点
if (key < node->key)
node->left = remove(node->left, key);
else if (key > node->key)
node->right = remove(node->right, key);
else { // 找到要删除的节点
// 节点只有一个子节点或没有子节点
if (node->left == nullptr || node->right == nullptr) {
AVLNode<T>* temp = node->left ? node->left : node->right;
// 没有子节点的情况
if (temp == nullptr) {
temp = node;
node = nullptr;
} else { // 有一个子节点的情况
*node = *temp; // 复制子节点的数据到当前节点
}
delete temp; // 释放内存
} else {
// 节点有两个子节点:获取右子树的最小键值
AVLNode<T>* temp = minValueNode(node->right);
// 复制后继节点的数据到当前节点
node->key = temp->key;
// 删除后继节点
node->right = remove(node->right, temp->key);
}
}
return fixBalance(node);
}
// 找到最小键值节点(辅助函数)
AVLNode<T>* minValueNode(AVLNode<T>* node) {
AVLNode<T>* current = node;
while (current->left != nullptr)
current = current->left;
return current;
}
// 平衡修复
AVLNode<T>* fixBalance(AVLNode<T>* node) {
if (!node) return nullptr;
// 更新高度
node->height = max(height(node->left), height(node->right)) + 1;
// 获取平衡因子
int balance = getBalance(node);
// 四种失衡情况处理
// 左左情况
if (balance > 1 && getBalance(node->left) >= 0)
return rightRotate(node);
// 左右情况
if (balance > 1 && getBalance(node->left) < 0) {
node->left = leftRotate(node->left); // 先左旋后右旋
return rightRotate(node);
}
// 右右情况
if (balance < -1 && getBalance(node->right) <= 0)
return leftRotate(node);
// 右左情况
if (balance < -1 && getBalance(node->right) > 0) {
node->right = rightRotate(node->right); // 先右旋后左旋
return leftRotate(node);
}
return node; // 未失衡,直接返回
}
// 查找节点(递归辅助函数)
bool search(AVLNode<T>* node, T key) const {
if (node == nullptr)
return false;
if (key == node->key)
return true;
else if (key < node->key)
return search(node->left, key);
else
return search(node->right, key);
}
// 中序遍历(辅助函数)
void inorder(AVLNode<T>* node) const {
if (node != nullptr) {
inorder(node->left);
cout << node->key << " ";
inorder(node->right);
}
}
// 销毁树(辅助函数)
void destroyTree(AVLNode<T>* node) {
if (node != nullptr) {
destroyTree(node->left);
destroyTree(node->right);
delete node;
}
}
public:
// 构造函数
AVLTree() : root(nullptr) {}
// 析构函数
~AVLTree() {
destroyTree(root);
}
// 插入接口
void insert(T key) {
root = insert(root, key);
}
// 删除接口
void remove(T key) {
root = remove(root, key);
}
// 查找接口
bool search(T key) const {
return search(root, key);
}
// 中序遍历接口
void inorder() const {
inorder(root);
cout << endl;
}
}; |
Beta Was this translation helpful? Give feedback.
-
K神,非常感谢你的讲解! def remove_helper(self, node: TreeNode | None, val: int) -> TreeNode | None:
"""递归删除节点(辅助方法)"""
if node is None:
return None
# 1. 查找节点并删除
if val < node.val:
node.left = self.remove_helper(node.left, val)
elif val > node.val:
node.right = self.remove_helper(node.right, val)
else:
if node.left is None or node.right is None:
child = node.left or node.right
# 子节点数量 = 0 ,直接删除 node 并返回
if child is None:
return None
# 子节点数量 = 1 ,直接删除 node
else:
node = child
else:
# 子节点数量 = 2 ,则将中序遍历的下个节点删除,并用该节点替换当前节点
temp = node.right
while temp.left is not None:
temp = temp.left
node.right = self.remove_helper(node.right, temp.val)
node.val = temp.val
# 更新节点高度
self.update_height(node)
# 2. 执行旋转操作,使该子树重新恢复平衡
return self.rotate(node)
|
Beta Was this translation helpful? Give feedback.
-
AVL树插入/删除之后,应该只需要对路径上第一个失衡节点做旋转,因为旋转会把高度更新限制在其子树内。不需要对整个路径都检查。 |
Beta Was this translation helpful? Give feedback.
-
我想问一个关于 红黑树的问题, 《算法导论》里面:
第13行, x.p 不已经是 y 了吗, 为什么要重新设置一下呢 ? k 神, 求解。 |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
chapter_tree/avl_tree/
Your first book to learn Data Structure And Algorithm.
https://www.hello-algo.com/chapter_tree/avl_tree/
Beta Was this translation helpful? Give feedback.
All reactions