ITPub博客

首页 > 应用开发 > IT综合 > STL容器内核:基于红黑树的set与map实现剖析

STL容器内核:基于红黑树的set与map实现剖析

投稿 IT综合 作者:bhluo 时间:2026-02-04 16:02:21 0 删除 编辑

# STL容器内核:基于红黑树的set与map实现剖析


在C++标准库的底层,set和map容器巧妙地共享同一颗红黑树骨架。这种设计展现了泛型编程的强大威力——用同一套数据结构支撑起两种截然不同的抽象接口。


## 红黑树基础:自平衡的二叉搜索树


红黑树是一种自平衡的二叉搜索树,它通过五个约束条件确保树的高度保持在对数级别:


```cpp

// 红黑树节点基本结构

enum Color { RED, BLACK };


template<typename T>

struct RBTreeNode {

    T data;

    Color color;

    RBTreeNode* parent;

    RBTreeNode* left;

    RBTreeNode* right;

    

    RBTreeNode(const T& val, Color c = RED)

        : data(val), color(c), parent(nullptr), 

          left(nullptr), right(nullptr) {}

};

```


红黑树的五个核心规则:

1. 每个节点要么红色,要么黑色

2. 根节点是黑色

3. 所有叶子节点(NIL节点)是黑色

4. 红色节点的两个子节点都是黑色

5. 从任一节点到其每个叶子的所有路径包含相同数目的黑色节点


## STL中的红黑树实现框架


STL实际使用更复杂的节点结构和模板设计:


```cpp

// 简化版STL红黑树节点结构

template<typename Value>

struct RBTreeNodeImpl {

    typedef RBTreeNodeImpl<Value>* LinkType;

    

    Value value_field;

    Color color;

    LinkType parent;

    LinkType left;

    LinkType right;

};


// 红黑树基类框架

template<typename Key, typename Value, typename KeyOfValue,

         typename Compare, typename Alloc = allocator<Value>>

class RBTree {

protected:

    typedef RBTreeNodeImpl<Value> RBTreeNode;

    

public:

    typedef Key key_type;

    typedef Value value_type;

    typedef Compare key_compare;

    

protected:

    RBTreeNode* header;      // 特殊头节点

    size_t node_count;       // 节点数量

    key_compare comp;        // 比较函数

    

    // 关键操作:左旋、右旋、插入修复、删除修复

    void rotate_left(RBTreeNode* x);

    void rotate_right(RBTreeNode* x);

    void insert_fixup(RBTreeNode* z);

    void erase_fixup(RBTreeNode* x);

    

public:

    // 迭代器支持

    iterator begin() { return leftmost(); }

    iterator end() { return header; }

    

    // 核心操作接口

    pair<iterator, bool> insert_unique(const value_type& x);

    iterator find(const key_type& k);

    size_type erase(const key_type& k);

    

private:

    // 内部辅助函数

    RBTreeNode* create_node(const value_type& x);

    void destroy_node(RBTreeNode* p);

    void insert(RBTreeNode* z);

    RBTreeNode* copy_tree(RBTreeNode* x, RBTreeNode* p);

};

```


## set的实现:基于红黑树的简单包装


set本质上是一个键值相同的红黑树容器:


```cpp

// set容器实现简析

template<typename Key, typename Compare = less<Key>,

         typename Alloc = allocator<Key>>

class set {

public:

    typedef Key key_type;

    typedef Key value_type;

    typedef Compare key_compare;

    typedef Compare value_compare;

    

private:

    // 关键:定义从值提取键的仿函数

    struct Identity {

        const key_type& operator()(const value_type& x) const {

            return x;  // set中键和值相同

        }

    };

    

    // 内部使用红黑树

    typedef RBTree<key_type, value_type, Identity,

                   key_compare, Alloc> RepType;

    RepType t;  // 实际的树容器

    

public:

    // 迭代器类型(底层树迭代器的包装)

    typedef typename RepType::const_iterator iterator;

    typedef typename RepType::const_iterator const_iterator;

    

    // 构造函数

    set() : t(Compare()) {}

    explicit set(const Compare& comp) : t(comp) {}

    

    template<typename InputIterator>

    set(InputIterator first, InputIterator last)

        : t(Compare()) {

        t.insert_range_unique(first, last);

    }

    

    // 容量操作

    bool empty() const { return t.empty(); }

    size_type size() const { return t.size(); }

    

    // 修改操作

    pair<iterator, bool> insert(const value_type& x) {

        return t.insert_unique(x);

    }

    

    template<typename InputIterator>

    void insert(InputIterator first, InputIterator last) {

        t.insert_range_unique(first, last);

    }

    

    // 查找操作

    iterator find(const key_type& x) const {

        return t.find(x);

    }

    

    size_type count(const key_type& x) const {

        return t.find(x) == t.end() ? 0 : 1;

    }

    

    // 删除操作

    size_type erase(const key_type& x) {

        return t.erase(x);

    }

    

    void erase(iterator position) {

        t.erase(position);

    }

    

    // 范围操作

    iterator lower_bound(const key_type& x) const {

        return t.lower_bound(x);

    }

    

    iterator upper_bound(const key_type& x) const {

        return t.upper_bound(x);

    }<"m4.s6k3.org.cn"><"a6.s6k3.org.cn"><"d3.s6k3.org.cn">

    

    // 交换

    void swap(set& other) {

        t.swap(other.t);

    }

    

    // 比较操作

    key_compare key_comp() const { return t.key_comp(); }

    value_compare value_comp() const { return t.key_comp(); }

};

```


## map的实现:键值分离的红黑树


map需要在红黑树节点中存储键值对:


```cpp

// map容器实现核心

template<typename Key, typename T, typename Compare = less<Key>,

         typename Alloc = allocator<pair<const Key, T>>>

class map {

public:

    typedef Key key_type;

    typedef T mapped_type;

    typedef pair<const key_type, mapped_type> value_type;

    typedef Compare key_compare;

    

private:

    // 从pair中提取键的仿函数

    struct SelectKey {

        const key_type& operator()(const value_type& x) const {

            return x.first;

        }

    };

    

    // 内部红黑树类型

    typedef RBTree<key_type, value_type, SelectKey,

                   key_compare, Alloc> RepType;

    RepType t;

    

public:

    // 迭代器类型

    typedef typename RepType::iterator iterator;

    typedef typename RepType::const_iterator const_iterator;

    

    // 构造函数

    map() : t(Compare()) {}

    explicit map(const Compare& comp) : t(comp) {}

    

    template<typename InputIterator>

    map(InputIterator first, InputIterator last)

        : t(Compare()) {

        t.insert_range_unique(first, last);

    }

    

    // 元素访问

    mapped_type& operator[](const key_type& k) {

        // 使用lower_bound和insert实现

        iterator i = lower_bound(k);

        if (i == end() || key_comp()(k, (*i).first)) {

            i = insert(i, value_type(k, mapped_type()));

        }

        return (*i).second;

    }

    

    mapped_type& at(const key_type& k) {

        iterator i = find(k);

        if (i == end()) {

            throw out_of_range("map::at");

        }

        return (*i).second;

    }

    

    const mapped_type& at(const key_type& k) const {

        const_iterator i = find(k);

        if (i == end()) {

            throw out_of_range("map::at");

        }

        return (*i).second;

    }

    

    // 插入操作

    pair<iterator, bool> insert(const value_type& x) {

        return t.insert_unique(x);

    }

    

    template<typename InputIterator>

    void insert(InputIterator first, InputIterator last) {

        t.insert_range_unique(first, last);

    }

    

    // 删除操作

    size_type erase(const key_type& x) {

        return t.erase(x);

    }

    

    void erase(iterator position) {

        t.erase(position);

    }

    

    void erase(iterator first, iterator last) {

        t.erase(first, last);

    }

    

    // 查找操作

    iterator find(const key_type& x) {

        return t.find(x);

    }

    

    const_iterator find(const key_type& x) const {

        return t.find(x);

    }

    

    // 容量操作

    bool empty() const { return t.empty(); }

    size_type size() const { return t.size(); }

    

    // 交换

    void swap(map& other) {

        t.swap(other.t);

    }

    

    // 比较操作

    key_compare key_comp() const { return t.key_comp(); }

    

    // 值比较器

    class value_compare {

        friend class map;

    protected:

        Compare comp;

        value_compare(Compare c) : comp(c) {}

    public:

        bool operator()(const value_type& x, const value_type& y) const {

            return comp(x.first, y.first);

        }

    };

    

    value_compare value_comp() const { return value_compare(key_comp()); }

};

```


## 迭代器设计:遍历红黑树的关键


红黑树迭代器需要支持中序遍历:


```cpp

// 红黑树迭代器实现框架

template<typename T, typename Ref, typename Ptr>

struct RBTreeIterator {

    typedef RBTreeIterator<T, T&, T*> iterator;

    typedef RBTreeIterator<T, const T&, const T*> const_iterator;

    typedef RBTreeIterator<T, Ref, Ptr> self;

    

    typedef bidirectional_iterator_tag iterator_category;

    typedef T value_type;

    typedef Ref reference;

    typedef Ptr pointer;

    typedef ptrdiff_t difference_type;

    

    typedef RBTreeNodeImpl<T>* LinkType;

    LinkType node;

    

    // 构造函数

    RBTreeIterator() : node(nullptr) {}

    explicit RBTreeIterator(LinkType x) : node(x) {}

    

    // 解引用操作符

    reference operator*() const { return node->value_field; }

    pointer operator->() const { return &(operator*()); }

    

    // 前向迭代

    self& operator++() {

        increment();

        return *this;

    }

    

    self operator++(int) {

        self tmp = *this;

        increment();

        return tmp;

    }

    

    // 后向迭代

    self& operator--() {

        decrement();

        return *this;

    }

    

    self operator--(int) {

        self tmp = *this;

        decrement();

        return tmp;

    }

    <"h7.s6k3.org.cn"><"v9.s6k3.org.cn"><"s2.s6k3.org.cn">

    // 比较操作

    bool operator==(const self& x) const { return node == x.node; }

    bool operator!=(const self& x) const { return node != x.node; }

    

private:

    // 关键:寻找中序遍历的下一个节点

    void increment() {

        if (node->right != nullptr) {

            // 如果有右子树,找右子树的最左节点

            node = node->right;

            while (node->left != nullptr) {

                node = node->left;

            }

        } else {

            // 否则找第一个左子树包含当前节点的祖先

            LinkType y = node->parent;

            while (node == y->right) {

                node = y;

                y = y->parent;

            }

            if (node->right != y) {

                node = y;

            }

        }

    }

    

    // 寻找中序遍历的前一个节点

    void decrement() {

        if (node->color == RED && node->parent->parent == node) {

            // 特殊情况:header节点

            node = node->right;

        } else if (node->left != nullptr) {

            // 如果有左子树,找左子树的最右节点

            node = node->left;

            while (node->right != nullptr) {

                node = node->right;

            }

        } else {

            // 否则找第一个右子树包含当前节点的祖先

            LinkType y = node->parent;

            while (node == y->left) {

                node = y;

                y = y->parent;

            }

            node = y;

        }

    }

};

```


## 性能特性与使用指导


基于红黑树的set和map具有以下性能特点:

- 插入、删除、查找:O(log n)时间复杂度

- 有序遍历:支持基于比较的有序遍历

- 内存使用:每个节点需要额外存储颜色和指针信息


```cpp

// 使用示例:统计单词频率

void countWordFrequency(const vector<string>& words) {

    map<string, int> wordCount;

    

    for (const auto& word : words) {

        // 自动处理重复键

        wordCount[word]++;

    }

    

    // 有序输出

    for (const auto& pair : wordCount) {

        cout << pair.first << ": " << pair.second << endl;

    }

}


// 使用示例:集合运算

void setOperations() {

    set<int> s1 = {1, 3, 5, 7, 9};

    set<int> s2 = {2, 3, 5, 7, 11};

    

    // 交集

    set<int> intersection;

    set_intersection(s1.begin(), s1.end(),

                     s2.begin(), s2.end(),

                     inserter(intersection, intersection.begin()));

    

    // 并集

    set<int> unionSet;

    set_union(s1.begin(), s1.end(),

              s2.begin(), s2.end(),

              inserter(unionSet, unionSet.begin()));

}

```


set和map的设计展现了C++模板和泛型编程的精髓:通过精心的抽象和复用,用同一套红黑树实现支撑起多个容器接口。这种设计不仅保证了代码的高效执行,还确保了不同容器间行为的一致性。理解这一底层实现,有助于开发人员更好地利用这些容器,并能在需要时实现自定义的关联容器。


来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/19545/viewspace-3109926/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2015-11-01

  • 博文量
    895
  • 访问量
    933967