如何实现红黑树节点指向存储同键值的另一红黑树的指针?
实现红黑树节点指向对应同键值红黑树的方案
我来拆解一下你的需求,核心是让原红黑树的每个节点关联到一棵包含所有相同键对应值的红黑树,并且原节点作为这棵子树的根。下面是分步实现的思路和代码示例:
1. 扩展红黑树节点结构
首先,我们需要给原红黑树的节点新增一个指针,用来指向对应子红黑树的根。这里用C++模板结构为例:
template <typename Key, typename Value> struct RedBlackNode { Key key; Value value; bool is_red; // 红黑树节点颜色:红为true,黑为false RedBlackNode* left; RedBlackNode* right; RedBlackNode* parent; RedBlackNode* sub_tree_root; // 新增:指向对应同键值红黑树的根 RedBlackNode(Key k, Value v) : key(k), value(v), is_red(true), left(nullptr), right(nullptr), parent(nullptr), sub_tree_root(nullptr) {} };
2. 遍历原树,按键分组收集所有值
先遍历原红黑树,把每个键对应的所有值收集到一个哈希映射里,这样后续构建子树时不用重复遍历原树:
template <typename Key, typename Value> void collectKeyValues(RedBlackNode<Key, Value>* root, unordered_map<Key, vector<Value>>& key_map) { if (!root) return; // 中序遍历红黑树,保证值的顺序(可选,根据你的需求调整) collectKeyValues(root->left, key_map); key_map[root->key].push_back(root->value); collectKeyValues(root->right, key_map); }
3. 构建同键值红黑树并关联指针
为了避免重复构建子树(同一个键只建一棵),我们用一个缓存映射记录每个键对应的子树根节点。然后遍历原树,给每个节点设置指针:
先实现红黑树插入及修复逻辑
子树必须遵守红黑树的5条性质,所以插入后需要做平衡调整:
template <typename Key, typename Value> void leftRotate(RedBlackNode<Key, Value>*& root, RedBlackNode<Key, Value>* x) { // 标准红黑树左旋实现 RedBlackNode<Key, Value>* y = x->right; x->right = y->left; if (y->left != nullptr) y->left->parent = x; y->parent = x->parent; if (!x->parent) root = y; else if (x == x->parent->left) x->parent->left = y; else x->parent->right = y; y->left = x; x->parent = y; } template <typename Key, typename Value> void rightRotate(RedBlackNode<Key, Value>*& root, RedBlackNode<Key, Value>* y) { // 标准红黑树右旋实现 RedBlackNode<Key, Value>* x = y->left; y->left = x->right; if (x->right != nullptr) x->right->parent = y; x->parent = y->parent; if (!y->parent) root = x; else if (y == y->parent->right) y->parent->right = x; else y->parent->left = x; x->right = y; y->parent = x; } template <typename Key, typename Value> void fixInsertion(RedBlackNode<Key, Value>*& root, RedBlackNode<Key, Value>* node) { // 红黑树插入后平衡修复逻辑 while (node->parent != nullptr && node->parent->is_red) { if (node->parent == node->parent->parent->left) { RedBlackNode<Key, Value>* uncle = node->parent->parent->right; if (uncle != nullptr && uncle->is_red) { node->parent->is_red = false; uncle->is_red = false; node->parent->parent->is_red = true; node = node->parent->parent; } else { if (node == node->parent->right) { node = node->parent; leftRotate(root, node); } node->parent->is_red = false; node->parent->parent->is_red = true; rightRotate(root, node->parent->parent); } } else { // 镜像逻辑,处理父节点是右子节点的情况 RedBlackNode<Key, Value>* uncle = node->parent->parent->left; if (uncle != nullptr && uncle->is_red) { node->parent->is_red = false; uncle->is_red = false; node->parent->parent->is_red = true; node = node->parent->parent; } else { if (node == node->parent->left) { node = node->parent; rightRotate(root, node); } node->parent->is_red = false; node->parent->parent->is_red = true; leftRotate(root, node->parent->parent); } } if (node == root) break; } root->is_red = false; // 根节点必须是黑色 } template <typename Key, typename Value> void insertIntoSubTree(RedBlackNode<Key, Value>*& root, RedBlackNode<Key, Value>* node) { // 插入节点到子红黑树 RedBlackNode<Key, Value>* parent = nullptr; RedBlackNode<Key, Value>* current = root; // 对于重复键,我们把新节点插入到右子树(可根据需求调整规则) while (current != nullptr) { parent = current; current = current->right; } node->parent = parent; if (!parent) root = node; else parent->right = node; // 修复红黑树平衡 fixInsertion(root, node); }
关联原节点与子树
遍历原树,为每个键构建子树,并设置指针:
template <typename Key, typename Value> void setupSubTreePointers(RedBlackNode<Key, Value>* root, unordered_map<Key, vector<Value>>& key_map) { if (!root) return; setupSubTreePointers(root->left, key_map); // 缓存每个键对应的子树根,避免重复构建 static unordered_map<Key, RedBlackNode<Key, Value>*> key_to_sub_root; if (key_to_sub_root.find(root->key) == key_to_sub_root.end()) { // 用当前原节点作为子树的根 RedBlackNode<Key, Value>* sub_root = root; // 插入所有同键的其他值 for (const auto& v : key_map[root->key]) { if (v == root->value) continue; // 跳过当前节点自己,避免重复 auto* new_node = new RedBlackNode<Key, Value>(root->key, v); insertIntoSubTree(sub_root, new_node); } key_to_sub_root[root->key] = sub_root; } // 设置当前节点的sub_tree_root指针 root->sub_tree_root = key_to_sub_root[root->key]; setupSubTreePointers(root->right, key_map); }
4. 整体执行流程
把上面的步骤串起来,完成整个关联过程:
// 假设original_root是你的原红黑树的根节点 unordered_map<KeyType, vector<ValueType>> key_map; collectKeyValues(original_root, key_map); setupSubTreePointers(original_root, key_map);
关键注意事项
- 重复键规则:如果原树允许重复键,需要明确重复键在子树中的插入位置(比如左/右子树),保证红黑树性质不被破坏。
- 内存管理:如果子树使用了新创建的节点,记得在销毁原树时同步释放子树节点的内存,避免泄漏。
- 同步更新:如果原树后续有插入/删除操作,需要同步更新对应的子树和指针,否则会出现数据不一致。
- 性能优化:用缓存映射(
key_to_sub_root)避免同一个键重复构建子树,大幅提升效率。
内容的提问来源于stack exchange,提问作者marinaaa
相关产品推荐
相关产品推荐

