您的位置:首页 > 产品设计 > UI/UE

深入剖析deque容器实现

2016-05-02 20:54 344 查看

deque简介

       deque是双向开口的连续性存储空间。虽说是连续性存储空间,但这种连续性只是表面上的,实际上它的内存是动态分配的,它在堆上分配了一块一块的动态储存区,每一块动态存储区本身是连续的,deque自身的机制把这一块一块的存储区虚拟地连在一起。

       它首次插入一个元素,默认会动态分配512字节空间,当这512字节空间用完后,它会再动态分配自己另外的512字节空间,然后虚拟地连在一起。deque的这种设计使得它具有比vector复杂得多的架构、算法和迭代器设计。它的性能损失比之vector,是几个数量级的差别。所以说,deque要慎用。

deque数据结构

        逻辑数据结构示意图:

                 


                                                              图1 逻辑结构示意图

        实际数据结构示意图:

                


                                                                 图2 实际结构示意图

 数据结构实现

template<class _Ty, class _Ax>
class deque
{
private:
_Mapptr _Map;		// pointer to array of pointers to blocks
size_type _Mapsize;	// size of map array
size_type _Myoff;	// offset of initial element
size_type _Mysize;	// current length of sequence
};
 一、deque的中控器      
        我们发现这里有一个_Map成员变量。大家注意,这可不是STL中的map。这个_Map是一个指针,指向一块特殊的内存地址,这里保存着指向deque动态申请的所有512字节内存空间的首地址。deque先用一段小的连续空间顺序存放了一个一个指针,然后这些顺序存放的指针再各自指向用来真正存放数据的512字节连续性空间。当_Map指向的这块空间不够存放内存指针的时候,就会另觅一块更大的连续性空间,然后把指针一个一个复制过去,并销毁旧的空间。利用这种数据结构,deque就能方便地模拟自身的存储区是连续性空间的假象,并且可以实现双向插入删除的功能,我们看一下deque的数据结构图,如图3所示。
               


                                                                      图 3 内部实现结构    
         _Map所指的一小块连续空间就是deque的中央控制器,其中每个元素(此处称为一个节点,node)都是指针,指向另一段(较大的)连续线性空间,称为缓冲区。缓冲区才是deque的储存空间主体。STL 允许我们指定缓冲区大小,默认值0表示将使用512
bytes 缓冲区。

          当中控器使用率已经满载时,便需要再找一块更大的空间来做map,配置策略间reallocate_map(),新的map可以容纳更多的节点,也就是更多的缓冲区,如图4是扩展新空间的示意图,新增缓冲区是在原来基础上进行,没有复制操作,这种扩展方式避开了“重新配置、复制、释放”的轮回,代价是复杂的迭代器架构。
       


                                                   图 4 扩展新空间实现方式 
     从deque扩展新空间的方式,可以看出deque没有capacity(),不需要reserce(size_type n)。这是因为deque由动态分配的连续空间组合而成,随时可以增加一段新的空间链接起来。它没有必要像vector那样“因旧空间不足而重新分配2倍的空间,然后复制元素,再释放旧空间。
 二、deque的迭代器
           在STL中,我们都可以通过解引用的方式得到迭代器所指的值,为了能够从“deque内部结构”中得到中某个元素的确切位置,那么deque的迭代器应该具备怎么结构,我们可以考虑以下几点。首先,需要知道该元素位于哪个缓冲区的哪个位置;其次,一旦迭代器前进和后退有可能会跳跃至上一个或下一个缓冲区,为了判断跳跃的条件就需要知道,当前元素所在缓冲区的首尾指针。最后,如果前进或后退必须跳跃至下一个或上一个缓冲区。为了能够正确跳跃,deque必须随时掌握管控中心(map),通过map可以知道跳跃的缓冲区。所以在迭代器中需要定义如下参数,deque的迭代器如图5所示:

当前元素的指针
当前元素所在缓冲区的起始指针,
当前元素所在缓冲区的尾指针,
指向map中指向所在缓区地址的指针。
  


                                                    图 5 迭代器示意图

deque对用户屏蔽了复杂的内存管理操作, 我们平时操时都是按照"逻辑结构"方式进行,也就是可动态插入、删除的一维数组,大大简化了用户使用,如图6所示。其实deque最大的任务就是管理这些分段的连续空间上,维护其整体连续的假象,并提供随机存取的接口。



图 6 deque<string>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息