返回

面试让我手写红黑树?搞什么飞机?

后端

红黑树:平衡二叉查找树的利器

在数据结构的世界里,红黑树扮演着举足轻重的角色。它是一种平衡二叉查找树,以其优异的查找、插入和删除性能而闻名。在面试中,红黑树往往成为考官的宠儿,因为它不仅考察求职者的数据结构基础,还考验了他们的算法能力和问题延伸性。

红黑树的原理与优势

红黑树巧妙地结合了二叉查找树和平衡树的特性。它是一棵二叉查找树,其中每个节点被标记为红色或黑色,并满足以下规则:

  • 根节点始终为黑色。
  • 每个红色节点的子节点都必须是黑色。
  • 每个节点与其子节点的黑色子节点数量相同。

这些规则保证了红黑树的平衡性,使得插入、删除和查找操作的时间复杂度保持在 O(log n) 的水平。

手把手教你实现红黑树

理解了红黑树的原理后,我们可以动手实现它。为了方便理解,我们以 C++ 为例,一步一步拆解它的实现过程。

定义节点结构

首先,我们需要定义节点结构:

struct Node {
    int key;
    Node* left;
    Node* right;
    bool color; // true 为红色,false 为黑色
};

插入操作

插入操作分为三个步骤:

  • 普通二叉查找树插入
  • 插入修复
  • 红黑规则检查
void insert(Node* &root, int key) {
    // 普通二叉查找树插入
    Node* new_node = new Node{key, nullptr, nullptr, true};
    insert_helper(root, new_node);
    fix_insert(root, new_node);
}

// 插入修复:如果父节点为红色,则需要进行旋转或颜色调整
void fix_insert(Node* &root, Node* new_node) {
    // 如果父节点为黑色,则无需修复
    if (root->color == false) {
        return;
    }
    // 如果叔叔节点为红色
    if (is_uncle_red(root)) {
        root->color = false;
        root->parent->color = false;
        root->parent->sibling->color = false;
    } else {
        // 如果新节点是右孩子且父节点是左孩子
        if (new_node == root->right && root == root->parent->left) {
            left_rotate(root);
            root = root->left;
        }
        // 如果新节点是左孩子且父节点是右孩子
        else if (new_node == root->left && root == root->parent->right) {
            right_rotate(root);
            root = root->right;
        }
        fix_insert(root, new_node);
    }
}

删除操作

删除操作也分为三个步骤:

  • 查找待删除节点
  • 删除修复
  • 红黑规则检查
void delete(Node* &root, int key) {
    Node* to_delete = find(root, key);
    delete_helper(root, to_delete);
    fix_delete(root, to_delete);
}

// 删除修复:如果删除节点为黑色,则需要进行旋转或颜色调整
void fix_delete(Node* &root, Node* to_delete) {
    // 如果删除节点为黑色,则需要修复
    if (to_delete->color == false) {
        if (to_delete == root) {
            return;
        }
        // 如果兄弟节点为红色
        if (is_sibling_red(to_delete)) {
            to_delete->parent->color = true;
            to_delete->sibling->color = false;
            // 如果兄弟节点的子节点均为黑色
            if (is_sibling_children_black(to_delete)) {
                fix_delete(root, to_delete->parent);
            } else {
                // 如果兄弟节点的右子节点为红色,且删除节点为左子节点
                if (to_delete == to_delete->parent->left && is_sibling_right_child_red(to_delete)) {
                    right_rotate(to_delete->sibling);
                }
                // 如果兄弟节点的左子节点为红色,且删除节点为右子节点
                else if (to_delete == to_delete->parent->right && is_sibling_left_child_red(to_delete)) {
                    left_rotate(to_delete->sibling);
                }
                to_delete->sibling->color = to_delete->parent->color;
                to_delete->parent->color = false;
                if (to_delete == to_delete->parent->left) {
                    right_rotate(to_delete->parent);
                } else {
                    left_rotate(to_delete->parent);
                }
            }
        } else {
            // 如果兄弟节点的子节点均为黑色
            if (is_sibling_children_black(to_delete)) {
                to_delete->sibling->color = true;
                fix_delete(root, to_delete->parent);
            } else {
                // 如果兄弟节点的右子节点为红色,且删除节点为左子节点
                if (to_delete == to_delete->parent->left && is_sibling_right_child_red(to_delete)) {
                    right_rotate(to_delete->sibling);
                }
                // 如果兄弟节点的左子节点为红色,且删除节点为右子节点
                else if (to_delete == to_delete->parent->right && is_sibling_left_child_red(to_delete)) {
                    left_rotate(to_delete->sibling);
                }
                to_delete->sibling->color = to_delete->parent->color;
                to_delete->parent->color = false;
                if (to_delete == to_delete->parent->left) {
                    right_rotate(to_delete->parent);
                } else {
                    left_rotate(to_delete->parent);
                }
                fix_delete(root, to_delete->parent);
            }
        }
    }
}

其他操作

除了插入和删除操作外,红黑树还支持查找、范围查询等操作,这些操作的实现与普通二叉查找树类似。

红黑树在面试中的地位

在面试中,红黑树扮演着举足轻重的角色。原因如下:

  • 数据结构基础: 红黑树考察了求职者对数据结构的基本理解,包括二叉树、查找树和平衡树的原理。
  • 算法能力: 实现红黑树需要对算法有深入的了解,如插入、删除、查找和旋转操作。
  • 问题延展性: 红黑树涉及多种数据结构和算法,为面试官提供了广阔的延伸讨论空间,深入考查求职者的技术功底。

常见问题解答

Q1:红黑树与普通的二叉查找树有什么区别?
A1:红黑树在二叉查找树的基础上增加了红黑规则,保证了树的平衡性,从而支持更快的操作。

Q2:红黑树的时间复杂度是多少?
A2:红黑树中的插入、删除和查找操作的时间复杂度均为 O(log n),其中 n 为树中的节点数。

Q3:红黑树的用途是什么?
A3:红黑树广泛应用于需要快速查找、插入和删除操作的数据结构中,如数据库、文件系统和网络路由器。

Q4:实现红黑树有哪些注意事项?
A4:实现红黑树时,需要注意维护红黑规则,包括插入后进行插入修复,删除后进行删除修复。

Q5:如何优化红黑树的性能?
A5:可以通过调整红黑规则或使用其他平衡树算法来优化红黑树的性能,如 AVL 树或 splay 树。