Deque:双向容器 特性概述
- 双向进出,可以使用push_back,push_front/(pop)来对容器元素进行初始化
- 结构:超级vector - 后面将一一展开
Deque:数据结构:
- 首先类比vector,vector 作为自增长连续内存容器,并不是完全动态增长的,它内部依靠内存空间的重新申请扩大+ 复制 + 释放原容器内存空间,来伪装内存上的动态扩展(代价是昂贵的)
- Deque 采用中控【管控】中心Map(vector<Node*>) + Node(vector -缓冲区:实际存储位置)来实现。
Class Data Member :
typedef T value_type; typedef value_type * pointer;
typedef simple_alloc<value_type,Alloc> data_allocator;
typedef simple_alloc<pointer,Alloc> map_allocator;
- Map(管控中心表示):typedef pointer * map_point; map_point map; size_type map_size ;
- 迭代器:typedef _deque_iterator<T,T&,T*,Bufsiz> iterator; iterator start,finish;
Class Function Member:
- void deque<T,Alloc,BufSize>::create_map_and_nodes(size_type num_elements) : 分别使用上面两个allocator来对空间进行分配
- void push_back(const value_type & t ) : if(finish.cur ! = finish.last - 1){construct(finish.cur,t); ++finish.cur;}else push_back_aux(t) //注意进行新node的申请(push_back_aux是当前node中剩下一个可用元素空间的时候调用)
- void deque<T,Alloc,BufSize>::push_back_aux(const value_type & t ) :reserve_map_at_back(); new_node = allocate_node();construct(finish.cur,t); finish.setNode(mew_node);finish.cur = finish.first; //得益于上一步中当当前node剩下 //一个元素的时候进行调用,所以本次申请结构简单,cur指向first就可以
- void push_front(const value_type & t ) : 同比类似于push_back,只不过为 -- finish.cur ,且边界条件改变,因为从后往前,开始以start.cur = start.last ,然而赋值却在start.cur -1 处调用构造函数 ,以下为源代码:if(start.cur != start.first) construct(start.cur -1 ); --start.cur;
- void deque<T,Alloc,BufSize>::push_front_aux(const value_type & t ) :对比以上
- void deque<T,Alloc,BufSize>::reallocate_map(size_type nodes_to_add,bool add_at_front) :reserve_map_at_front/back都是调用这个函数,仅仅判断条件不一样(都是在判断Map Front/Back是否还有下一个可用阶段);分两个判断:第一个判断:当前使用的start-finish+1+new_added_node(包括新申请的node数量)是否到达map_size的一半?是否规范? 如果老是使用push_back必然会导致 Map后面的node*都被填满 (这个地方忘记讲了,为了平衡Deque存储效率,map并不是以map[0]作为起始,因为它是双向进出,所以以一半为开始点),这个地方会在不申请新空间的基础上,从新调整start和finish的位置,当new_start的位置小于start,此阿勇copy() ,否则采用copy_backward() (考虑到Copy时的覆盖问题);第二个判断会重新申请Map的空间,然后调整并拷贝原Map中的数据
- void pop_back(const value_type & t ) : 类比push_back,对称:调用destroy函数释放空间,将finish.cur --, 如果说push_back需要考虑的是node扩容问题,那么pop_back需要考虑的就是缩node的问题(释放node)
- void pop_front(const value_type & t ) : 类比同push_front
- vdeque<T,Alloc,BufSize>::iterator deque<T,Alloc,BufSize>::erase (iterator first, iterator last ) : 从前面或者后面删除都是简单的,因为不涉及到删除后的顺位问题。而连续内存容器删除是耗费极大的,虽然deque规避了在扩容时的复制开销,但是无法避免删除时的顺位复制开销。如何减少元素的移动则是至关重要的。 Deque容器,以删除区域为边界,计算删除区域前到start的元素数量,以及删除区域尾端到finish的元素数量n,考虑是前移调整start起始点,还是后端移动调整finish结束点
Deque:迭代器设计
Struct Data Member :
- 其中指出Deque迭代器是Random类型即:typedef random_access_iterator_tag iterator_cateory
- T * cur ; //当前node缓冲区中的下一个可用元素的位置
- T * first ; // 当前node缓冲区的第一个元素的位置
- T * last; /// 当前node缓冲区的最后一个有效元素的下一个位置(包含备用空间)
- map_pointer node //指向管控中心当前node的首地址
Deque容器在整体上显示连续性,完全归功于迭代器内部对++,--,[] (下标操作符),-, + 运算符的重载,使得用户感觉不到在node缓冲区间的跳转。