map内存结构

来源:互联网 发布:上瘾网络剧未删减资源 编辑:程序博客网 时间:2024/05/16 09:49

GNU实现的std::map的数据结构模型是红黑树。红黑树是平衡二叉树的一类变种。可以保证在最坏情况下花费O(logN)时间。

其着色性质有如下特性:

1,根节点是黑色的

2,每个节点要么是红色,要么是黑色

3,如果一个节点是红色,其子节点必须是黑色。

4,从一个节点到一个NULL指针的每一条路径必须包含相同数目的黑色节点

由上面的几条特性可以推论出,查找是一个对数操作。

 

我写了一个简单的例子

#include <string>
#include <map>

int main(int argc, char * argv[])
{
    typedef std::pair<int, std::string> cpair;
    std::map<int, std::string> map;

    map.insert(cpair(3, "c"));
    
    map.insert(cpair(1, "a"));
    
    map.insert(cpair(4, "d"));
    
    map.erase(3);
    
    return 0;
}

 

使用gbd在map.insert(cpair(3, "c"))后加了断点

可以看到,map的实现在_M_t中

map = {_M_t = {
    _M_impl = {<std::allocator<std::_Rb_tree_node<std::pair<int const, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >> = {<__gnu_cxx::new_allocator<std::_Rb_tree_node<std::pair<int const, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >> = {<No data fields>}, <No data fields>}, _M_key_compare = {<std::binary_function<int, int, bool>> = {<No data fields>}, <No data fields>}, _M_header = {_M_color = std::_S_red, _M_parent = 0x80f2010, _M_left = 0x80f2010, _M_right = 0x80f2010}, _M_node_count = 1}}}

 

可以看到在map内存的尾部保存了红黑树的着色信息和左右子树。

 

在map.insert(cpair(1, "a"));后继续加断点

map = {_M_t = {
    _M_impl = {<std::allocator<std::_Rb_tree_node<std::pair<int const, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >> = {<__gnu_cxx::new_allocator<std::_Rb_tree_node<std::pair<int const, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >> = {<No data fields>}, <No data fields>}, _M_key_compare = {<std::binary_function<int, int, bool>> = {<No data fields>}, <No data fields>}, _M_header = {
        _M_color = std::_S_red, _M_parent = 0x80f2010, _M_left = 0x80f2048, _M_right = 0x80f2010}, _M_node_count = 2}}}

 

由于key值1比3小,所以按照平衡树的规则,插入在左节点上

 

继续在map.insert(cpair(4, "d"));后加断点

map = {_M_t = {
    _M_impl = {<std::allocator<std::_Rb_tree_node<std::pair<int const, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >> = {<__gnu_cxx::new_allocator<std::_Rb_tree_node<std::pair<int const, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >> = {<No data fields>}, <No data fields>}, _M_key_compare = {<std::binary_function<int, int, bool>> = {<No data fields>}, <No data fields>}, _M_header = {
        _M_color = std::_S_red, _M_parent = 0x80f2010, _M_left = 0x80f2048, _M_right = 0x80f2080}, _M_node_count = 3}}}

 

可以看到map的右子树变化了,由于key值4比3大,所以插入到右节点上。

同时可以看到_M_node_count的节点信息随着插入而增长

在erase后加断点

map = {_M_t = {
    _M_impl = {<std::allocator<std::_Rb_tree_node<std::pair<int const, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >> = {<__gnu_cxx::new_allocator<std::_Rb_tree_node<std::pair<int const, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >> = {<No data fields>}, <No data fields>}, _M_key_compare = {<std::binary_function<int, int, bool>> = {<No data fields>}, <No data fields>}, _M_header = {
        _M_color = std::_S_red, _M_parent = 0x80f2080, _M_left = 0x80f2048, _M_right = 0x80f2080}, _M_node_count = 2}}}

_M_node_count 节点总数少一个,而红黑树进行一次单旋转,改变了父节点的值。有此我们可知

由于每次插入和删除过程,红黑树要进行旋转以保证符合上述的4条原则。所以使用在删除或者插入后,迭代器指向的内容不确定,所以不要在删除或者插入后使用迭代器。

而且map标准库的实现是非线程安全的,使用的时候注意多线程问题


0 0
原创粉丝点击