STL源码分析之deque有序容器 上

前言

deque的功能很强大, 其复杂度也比list, vector复杂很多. deque是一个random_access_iterator_tag类型. 前面分析过vector是保存在连续的线性空间, 头插入和删除其代价都很大, 当数组满了还要重新寻找更大的空间; deque也是一个保存在连续的线性空间中, 但是它是一个双向开口, 头尾插入和删除都是O(1)的时间复杂度, 空间也是可扩展的, 不会经常寻找新的空间. deque的内存操作主要是由map来实现的.

打算分为3节来分析deque的重要实现部分. 本节分析deque的迭代器和构造析构函数.

__deque_iterator迭代器结构

虽然deque在某些方面和vector有些相似, 但是迭代器并不是一个普通指针, 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));
}
类型定义

dequerandom_access_iterator_tag类型. 满足traits编程.

这里重点分析四个参数cur, first, last以及node

#ifndef __STL_NON_TYPE_TMPL_PARAM_BUG
template <class T, class Ref, class Ptr, size_t BufSiz>
struct __deque_iterator {
   
	// 迭代器定义
  typedef __deque_iterator<T, T&, T*, BufSiz>             iterator;
  typedef __deque_iterator<T, const T&, const T*, BufSiz> const_iterator;
  static size_t buffer_size() {
   return __deque_buf_size(BufSiz, sizeof(T)); }
#else /* __STL_NON_TYPE_TMPL_PARAM_BUG */
template <class T, class Ref, class Ptr>
struct __deque_iterator {
   
  typedef __deque_iterator<T, T&, T*>             iterator;
  typedef __deque_iterator<T, const T&, const T*> const_iterator;
  static size_t buffer_size() {
   return __deque_buf_size(0, sizeof(T)); }
#endif
	// deque是random_access_iterator_tag类型
  typedef random_access_iterator_tag iterator_category;
  // 基本类型的定义, 满足traits编程
  typedef T value_type;
  typedef Ptr pointer;
  typedef Ref reference;
  typedef size_t size_type;
  typedef ptrdiff_t difference_type;
  // node
  typedef T** map_pointer;
  map_pointer node;
	
  typedef __deque_iterator self;
  ...
};
// 满足traits编程
template <class T, class Ref, class Ptr, size_t BufSiz>
inline random_access_iterator_tag
iterator_category(const __deque_iterator<T, Ref, Ptr, BufSiz>&) {
   
  return random_access_iterator_tag();
}
template <class T, class Ref, class Ptr, size_t BufSiz>
inline T* value_type(const __deque_iterator<T, Ref, Ptr, BufSiz>&) {
   
  return 0;
}
template <class T, class Ref, class Ptr, size_t BufSiz>
inline ptrdiff_t* distance_type(const __deque_iterator<T, Ref, Ptr, BufSiz>&) {
   
  return 0;
}

cur, first, last这三个变量类似于vector中的3个迭代器一样.

  • cur : 当前所指的位置
  • first : 当前数组中头的位置
  • last : 当前数组中尾的位置

注意 : 因为deque的空间是由map管理的, 它是一个指向指针的指针, 所以三个参数都是指向当前的数组, 这样的数组可能有多个, 只是每个数组都管理这3个变量.

template <class T, class Ref, class Ptr, size_t BufSiz>
struct __deque_iterator {
   
	...
  typedef T value_type;
  T* cur;
  T* first;
  T* last;
  ...
};

每一个数组都有一个node指针, 他是用来指向*map的指针.

template <class T, class Ref, class Ptr, size_t BufSiz>
struct __deque_iterator {
   
	...
	// node
  typedef T** map_pointer;
  map_pointer node;
  ...
};
构造函数
template <class T, class Ref, class Ptr, size_t BufSiz>
struct __deque_iterator {
   
	...
  	// 初始化cur指向当前数组位置, last指针数组的尾, node指向y
  	__deque_iterator(T* x, map_pointer y)  : cur(x), first(*y), last(*y + buffer_size()), node(y) {
   }
  	// 初始化为一个空的deque
  	__deque_iterator() : cur(0), first(0), last(0), node(0) {
   }
  	// 接受一个迭代器
  	__deque_iterator(const iterator& x) : cur(x.cur), first(x.first), last(x.last), node(x.node) {
   }
    ...
};
重载

__deque_iterator实现了基本运算符, deque重载的运算符操作都是调用__deque_iterator的运算符.

不过先分析一个待会会用到的函数set_node.

因为node是一个指向*map的指针, 当数组填充满了后, 要重新指向下一个数组的头, set_node就是更新指向数组的头的功能.

template <class T, class Ref, class Ptr, size_t BufSiz>
struct __deque_iterator {
   
	...
	void set_node(map_pointer new_node) 
	{
   
		// 让node指针另一个数组的头, 同时修改头和尾的地址
    	node = new_node;
    	first = *new_node;
    	last = first + difference_type(buffer_size());
  	}
  	...
};

重载++和–

需要注意++和–都可能出现数组越界, 如果判断要越界就得更新node的指向.

template <class T, class Ref, class Ptr, size_t BufSiz>
struct __deque_iterator {
   
	...  
 	// 这里需要判断是否达到当前数组的尾部
  self& operator++() {
   
    ++cur;
    // 达到了尾部就需要更新node的指向
    if (cur == last) {
   
      set_node(node + 1);
      cur = first;
    }
    return *this; 
  }
  // 同理, 需要判断是否到达数组的头. 到达就要更新node指向
  self& operator--() {
   
    if (cur == first) {
   
      set_node(node - 1);
      cur = last;
    }
    --cur
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值