Boolan/STL 与泛型编程 part3

2017-12-05 12:46:54 / herohlc


deque深度探索

1. deque数据结构

Image Copied on 2017-12-10 at 16.48.33 下午.png

体会外部的设计思路。deque对外特性连续,内部分段连续。

2. deque缓冲区

deque如何实现前后扩充?
缓冲区帮助deque实现前后扩充

deque缓冲区设计

  1. 分段缓冲区存储

deque实际存入的元素放在缓冲区中,deque中会创建多个缓冲区供插入数据。

  1. 缓冲区管理

多个缓冲区元素在一个map形式数据中(vector实现)中管理,缓冲区元素分布在map的中间位置,向两侧扩充。当map充满后自动扩充(vector扩充)。

3. deque迭代器设计

deque如何实现连续访问?
deque iterator帮助deque实现连续访问

iterator的四个变量

Image Copied on 2017-12-10 at 16.50.30 下午.png
  1. cur: 迭代器在一个deque中当前指向的元素
  2. first: 迭代器当前指向的缓冲区中,缓冲区范围中的第一个元素的位置
  3. last: 迭代器当前指向的缓冲区中,缓冲区范围中的最后一个元素的下一个元素位置
  4. node: 指向map区
    注意: iterator四个变量的变化规律
  5. iterator在一个缓冲区中移动时,cur在变化,其他不变
  6. iterator切换缓冲区移动时,所有变量都在变。

iterator移动行为

  1. iterator在缓冲区存储元素的范围内移动。
  2. iterator如果移动到缓冲区的边界(first/last),则通过node返回map,找到下一个缓冲区。

4. deque 对象存储的两个迭代器 begin/end

所有的容器都会存储两个迭代器,begin/end

template <class T, class Alloc = alloc, size_t Buffsiz = 0>
class deque {
    ...
protected:
    iterator start;
    iterator finish;
    ...
}

5. 源码

deque

// g++ 2.95.1 stl_deque.h
template <class _Tp, class _Alloc, size_t __bufsiz>
class _Deque_base {
public:
#ifndef __STL_NON_TYPE_TMPL_PARAM_BUG
  typedef _Deque_iterator<_Tp,_Tp&,_Tp*,__bufsiz>              iterator;
  typedef _Deque_iterator<_Tp,const _Tp&,const _Tp*, __bufsiz> const_iterator;
#else /* __STL_NON_TYPE_TMPL_PARAM_BUG */
  typedef _Deque_iterator<_Tp,_Tp&,_Tp*>                      iterator;
  typedef _Deque_iterator<_Tp,const _Tp&,const _Tp*>          const_iterator;
#endif /* __STL_NON_TYPE_TMPL_PARAM_BUG */

  typedef _Alloc allocator_type;
  allocator_type get_allocator() const { return allocator_type(); }

  _Deque_base(const allocator_type&, size_t __num_elements)
    : _M_map(0), _M_map_size(0),  _M_start(), _M_finish() {
    _M_initialize_map(__num_elements);
  }
  _Deque_base(const allocator_type&)
    : _M_map(0), _M_map_size(0),  _M_start(), _M_finish() {}
  ~_Deque_base();    

protected:
  void _M_initialize_map(size_t);
  void _M_create_nodes(_Tp** __nstart, _Tp** __nfinish);
  void _M_destroy_nodes(_Tp** __nstart, _Tp** __nfinish);
  enum { _S_initial_map_size = 8 };

protected:
  _Tp** _M_map;
  size_t _M_map_size;  
  iterator _M_start;
  iterator _M_finish;

  typedef simple_alloc<_Tp, _Alloc>  _Node_alloc_type;
  typedef simple_alloc<_Tp*, _Alloc> _Map_alloc_type;

  _Tp* _M_allocate_node()
    { return _Node_alloc_type::allocate(__deque_buf_size(__bufsiz, 
                                                         sizeof(_Tp))); }
  void _M_deallocate_node(_Tp* __p)
    { _Node_alloc_type::deallocate(__p, __deque_buf_size(__bufsiz, 
                                                         sizeof(_Tp))); }
  _Tp** _M_allocate_map(size_t __n) 
    { return _Map_alloc_type::allocate(__n); }
  void _M_deallocate_map(_Tp** __p, size_t __n) 
    { _Map_alloc_type::deallocate(__p, __n); }
};

iterator

// g++ 2.95.1 stl_deque.h
template <class _Tp, class _Ref, class _Ptr>
struct _Deque_iterator {
  typedef _Deque_iterator<_Tp, _Tp&, _Tp*>             iterator;
  typedef _Deque_iterator<_Tp, const _Tp&, const _Tp*> const_iterator;
  static size_t 
    _S_buffer_size() { return __deque_buf_size(0, sizeof(_Tp)); }

  typedef random_access_iterator_tag iterator_category;
  typedef _Tp value_type;
  typedef _Ptr pointer;
  typedef _Ref reference;
  typedef size_t size_type;
  typedef ptrdiff_t difference_type;
  typedef _Tp** _Map_pointer;

  typedef _Deque_iterator _Self;

  _Tp* _M_cur;
  _Tp* _M_first;
  _Tp* _M_last;
  _Map_pointer _M_node;
...
  }

注意其中的 associate types

6. buffer size

指定缓冲区大小.
注意:
这里的大小是指缓冲区数组的个数,而不是缓冲区实际内存大小。

template<class T, class Alloc = alloc, size_t Buffsiz=0>
class deque{
...
}

inline size_t __deque_buf_size(size_t n, size_t sz) {
    return n!=0 ? n : (sz < 512 ? size_t(512/sz) : size_t(1));
}  // sz 为sizeof(value_type)

其中 template中size_t 的用法是新的知识点

template <class T, class Alloc = alloc, size_t Buffersiz = 0>
class deque{
    ...
}
  1. 新版本不再支持用户指定缓冲区大小

7. deque<T>::insert()

iterator insert(iterator position, const value_type x) {
    if(position.cur == start.cur) {
        push_front(x);
        return start;
    } else if(position.cur == finish.cur) {
        push_back(x);
        iterator tmp = finish;
        --tmp;
        return tmp;
    } else {
        return insert_aux(position, x);
    }
}

// g++ 2.95.1 stl_deque.h
template <class _Tp, class _Alloc, size_t __bufsize>
typename deque<_Tp, _Alloc, __bufsize>::iterator
deque<_Tp,_Alloc,__bufsize>::_M_insert_aux(iterator __pos,
                                           const value_type& __x)
{
  difference_type __index = __pos - _M_start;
  value_type __x_copy = __x;
  if (__index < size() / 2) {
    push_front(front());
    iterator __front1 = _M_start;
    ++__front1;
    iterator __front2 = __front1;
    ++__front2;
    __pos = _M_start + __index;
    iterator __pos1 = __pos;
    ++__pos1;
    copy(__front2, __pos1, __front1);
  }
  else {
    push_back(back());
    iterator __back1 = _M_finish;
    --__back1;
    iterator __back2 = __back1;
    --__back2;
    __pos = _M_start + __index;
    copy_backward(__pos, __back2, __back1);
  }
  *__pos = __x_copy;
  return __pos;
}

注意:

  1. Insert 插入元素到已有元素位置时,已有元素需要向一侧推动。
  2. Insert在推动元素时,需要考虑向头一侧推动还是向尾一侧推动,谁的效率更高。
  3. 推动元素会造成已有元素的析构和新元素的构造。

理解:

  1. 对于deque,insert操作会造成元素的推动,推动的过程会有元素的copy/构造等操作,造成效率问题,但在头尾的push不会有元素的推动,相对来说效率会高。

queue&stack深度探索

未完待续


RB-tree深度探索

未完待续


set/multiset深度探索

未完待续


map/multimap深度探索

未完待续


hash table深度探索

未完待续


hash_set/has_multiset, hash_map/hash_multimap概念

未完待续


unordered容器概念

未完待续


©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 162,475评论 4 372
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,744评论 2 307
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 112,101评论 0 254
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,732评论 0 221
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 53,141评论 3 297
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 41,049评论 1 226
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,188评论 2 320
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,965评论 0 213
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,716评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,867评论 2 254
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,341评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,663评论 3 263
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,376评论 3 244
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,200评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,990评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,179评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,979评论 2 279

推荐阅读更多精彩内容