STL笔记_deque

deque:双向开口连续线性空间,由一段一段的定量连续空间构成,可以在首尾两端分别做元素的插入和删除操作。

与vector的差异:1.deque允许于常数时间内对头端进行元素的插入和删除;2.deque没有容量的观念,因为它是动态地以分段连续空间组合而成,随时可以增加一段新的空间并链接起来。

虽然deque也提供Ramdon Access Iterator,但它的迭代器并不是普通指针,其复杂度远大于vector的。

中控器

deque由一块所谓的map(非map容器)作为主控。这里的map是一小块连续空间,其中每个元素(此处称为一个节点,node)都是指针,指向另一端(较大的)连续线性空间,成为缓冲区。缓冲区是deque的存储空间主体。SGI STL允许我们指定缓冲区大小,默认值0表示使用512bytes缓冲区。

template<class T,class Alloc=alloc,size_t Bufsize=0>
class deque {
public://基础类型
	typedef T value_type;
	typedef value_type* pointer;
...
protected://内置定义
	//元素的指针的指针
	typedef pointer* map_pointer;

protected://数据成员
	map_pointer map;//指向map,map是块连续空间,其内的每个元素都是一个指针,指向一块缓冲区
	size_type map_size;//map内可容纳多少指针
...
};

迭代器

template<class T,class Ref,class Ptr,size_t Bufsiz>
struct __deque_iterator
{//未继承std::iterator
	typedef __deque_iterator<T, T&, T*, Bufsiz> iterator;
	typedef __deque_iterator<T, const T&, const T*, Bufsiz> const_iterator;
	statirc size_t buffer_size() { return __deque_buf_size(Bufsiz, sizeof(T)); }


	typedef random_access_iterator_tag iterator_category;
	typedef T value_type;
	typedef Ptr pointer;
	typedef Ref reference;
	typedef size_t size_type;
	typedef ptrdiff_t difference_type;
	typedef T** map_pointer;
	typedef __deque_iterator self;
	//保持与容器的连结
	T* cur;//此迭代器所指之缓冲区中的现行元素
	T* first;//此迭代器所指之缓冲区的头
	T* last;//此迭代器所指之缓冲区的尾(含备用空间)
	map_pointer node;//指向管控中心
...
};
//如果n不为0,传回n,表示buffer size由用户自定义
//如果n为0,表示buffer size使用默认值,那么
//如果sz(元素大小,sizeof(value_type)小于512,传回512/sz
//如果sz不小于512,传回1
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));
}

deque迭代器在行进时一旦遇到缓冲区边缘要特别当心,视前进和后退而定,可能需要调用set_node()跳一个缓冲区。

void set_node(map_pointer new_node) {
		node = new_node;
		first = *new_node;
		last = first + difference_type(buffer_size());
	}

	reference operator*()const { return *cur; }
	pointer operator->()const { return &(operator*()); }
	difference_type operator-(const self& x)const {
		return difference_type(buffer_size())*(node - x.node - 1) + (cur - first) + (x.last - x.cur);
	}

	self& operator++() {
		++cur;
		if (cur == last)
		{
			set_node(node + 1);
			cur = first;
		}
		return *this;
	}
	self operator++(int) {
		self tmp = *this;
		++*this;
		return tmp;
	}
	self& operator--() {
		if (cur == first) {
			set_node(node - 1);
			cur = last;
		}
		--cur;
		return *this;
	}
	self operator--(int) {
		self tmp = *this;
		--*this;
		return tmp;
	}
	//以下实现随机存取,迭代器直接跳跃n个距离
	self& operator+=(difference_type n) {
		difference_type offset = n + (cur - first);
		if (offset >= 0 && offset < difference_type(buffer_size()))
			//目标在同一缓冲区内
			cur += n;
		else {
			//目标不在同一缓冲区内
			difference_type node_offset =
				offset > 0 ? offset / difference_type(buffer_size())
				: -difference_type((offset - 1) / buffer_size()) - 1;
			//切换至正确的节点(即缓冲区)
			set_node(node + node_offset);
			//切换至正确的元素
			cur = first + (offset - node_offset*difference_type(buffer_size()));
		}
		return *this;
	}
	self operator+(difference_type n)const {
		self tmp = *this;
		return tmp += n;
	}
	self& operator-=(difference_type n) {
		return *this += -n;
	}
	self operator-(difference_type n)const {
		self tmp = *this;
		return tmp -= n;
	}
	//以下实现随机存取,迭代器可以直接跳跃n个距离
	reference operator[](difference_type n)const { return *(*this + n); }
	bool operator==(const self& x)const { return cur == x.cur; }
	bool operator!=(const self& x)const { return !(*this == x); }
	bool operator<(const self& x)const {
		return (node == x.node) ? (cur < x.cur) : (node < x.node);
	}

数据结构

deque除了维护指向map的指针外,也维护start,finish两个迭代器,分别指向第一缓冲区的第一个元素和最后缓冲区的最后一个元素(的下一个位置),此外,它还必须记住当前map大小,因为一旦map所提供的节点不足,就必须重新配置更大的一块map。

	template<class T, class Alloc = alloc, size_t Bufsiz = 0>
	class deque {
	public:
		typedef T value_type;
		typedef value_type* pointer;
		typedef size_t size_type;

	public:
		typedef __deque_iterator<T, T&, T*, Bufsiz> iterator;

	protected:
		typedef pointer* map_pointer;

	protected:
		iterator start;//表现第一个节点
		iterator finish;//表现最后一个节点

		map_pointer map;//指向map,map是块连续空间,每个元素都是个指针,指向一个节点(缓冲区)

		size_type map_size;//map有多少指针

	public:
		iterator begin() { return start; }
		iterator end() { return finish; }

		reference operator[](size_type n) {
			return start[difference_type(n)];
		}

		reference front() { return *start; }
		reference back() {
			iterator tmp = finish;
			--tmp;
			return *tmp;
		}

		size_type size() const { return finish - start; }
		size_type max_size()const { return size_type(-1); }
		bool empty() const { return finish == start; }
	};

构造和内存管理:ctor,push_back,push_front

deque自行定义两个专属的空间配置器:

protected:
		//专属空间配置器,每次配置一个元素大小
		typedef simple_alloc<value_type, Alloc>data_allocator;
		//专属空间配置器,每次配置一个指针大小
		typedef simple_alloc<pointer, Alloc>map_allocator;
		//constructor
		deque(int n, const value_type& value):
			start(),finish(),map(0),map_size(0)
		{
			fill_initialize(n, value);
		}

		template<class T,class Alloc,size_t Bufsize>
		void deque<T, Alloc, Bufsize>::fill_initialize(size_type n, const value_type& value) {
			create_map_and_nodes(n);//把deque的结构产生并安排好
			map_pointer cur;
			__STL_TRY{
				//为每个节点缓冲区设定初值
				for (cur = start.node; cur < finish.node; ++cur)
				uninitialized_fill(*cur,*cur + buffer_size(),value);
			//最后一个节点的尾端可能有备用空间,不必设初值
			uninitialized_fill(finish.first, finish.cur, value);
			}
				catch (...) {
				...
			}
		}
		template<class T,class Alloc,size_t Bufsize>
		void deque<T, Alloc, Bufsize>::create_map_and_nodes(size_type num_elements)
		{
			//需要节点数=(元素个数/每个缓冲区可容纳的元素个数)+1
			//如果刚好整除,会多配一个节点
			size_type num_nodes = num_elements / buffer_size() + 1;

			//一个map要管理几个节点,最少8个,最多是“所需节点数加2”
			//前后个预留一个,扩充时可用
			map_size = max(initial_map_size(), num_nodes + 2);
			map = map_allocator::allocate(map_size);
			//以上配置出具有map_size个节点的map

			//以下令nstart和nfinish指向map所拥有之全部节点的最中央区段
			//保持在最中央,可使头尾两端的扩充能量一样大,每个节点可对应一个缓冲区
			map_pointer nstart = map + (map_size - num_nodes) / 2;
			map_pointer nfinish = nstart + num_nodes - 1;

			map_pointer cur;
			__STL_TRY{
				//为map内的每个现用节点配置缓冲区,
				//所有缓冲区加起来就是deque的可用空间
				//最后一个缓冲区可能留有余裕
				for (cur = nstart; cur < nfinish; ++cur)
				*cur = allocate_node();
			}
				catch(...){...}
			//为deque内的两个迭代器start和end设定正确内容
			start.set_node(nstart);
			finish.set_node(nfinish);
			start.cur = start.first;
			finish.cur = finish.first + num_elements%buffer_size();
		}

push_back():

public:
		void push_back(const value_type& t) {
			if (finish.cur != finish.last - 1) {
				//最后缓冲区尚有两个以上的元素备用空间
				costruct(finish.cur, t);//直接在备用空间上构造元素
				++finish.cur;//调整最后缓冲区的使用状态
			}
			else//最后缓冲区只剩一个元素备用空间
				push_back_aux(t);
		}

		template<class T,class Alloc,size_t Bufsize>
		void deque<T, Alloc, Bufsize>::push_back_aux(const value_type& t) {
			value_type t_copy = t;
			reserve_map_at_back();//若符合某种条件就必须重换一个map
			*(finish.node + 1) = allocate_node();//配置一个新节点
			__STL_TRY{
			construct(finish.cur,t_copy);//针对标的元素设值
			finish.set_node(finish.node + 1);//改变finish,令其指向新节点
			finish.cur = finish.first;//设定finish的状态
			}
			__STL_UNWIND(deallocate_node(*(finish.node + 1)));
		}

push_front():

public:
		void push_front(const value_type& t) {
			if (start.cur != first) {
				construct(start.cur - 1, t);
				--start.cur;
			}
			else
				push_front_aux(t);
		}
		//只有第一个缓冲区没有备用空间时才会被调用
		template<class T,class Alloc,size_t Bufsize>
		void deque<T, Alloc, Bufsize>::push_front_aux(const value_type& t)
		{
			value_type t_copy = t;
			reserve_map_at_front();//若符合某种条件则必须换一个map
			*(start.node - 1) = allocate_node();//配置一个新节点
			__STL_TRY{
			start.set_node(start.node + 1);
			start.cur = start.last - 1;
			construct(start.cur, t_copy);
			}
				catch (...) {
				start.set_node(start.node + 1);
				start.cur = start.first;
				deallocate_node(*(start.node - 1));
				throw;
			}
		}

对map重新整治的reserve_map_at_back()和reserve_map_at_front()实际操作由reallocate_map()执行:

void reserve_map_at_back(size_type nodes_to_add = 1)
		{
			if (nodes_to_add + 1 > map_size - (finish.node - map))
				//如果map尾端的节点备用空间不足
				//符合以上条件则必须换一个map(配置更大的,拷贝原来的,释放原来的)
				reallocate_map(nodes_to_add, false);
		}
		void reserve_map_at_front(size_type nodes_to_add = 1) {
			if (nodes_to_add > start.node - map)
				//如果map前端的节点备用空间不足
				//符合以上条件则必须换一个map(配置更大的,拷贝原来的,释放原来的)
				reallocate_map(nodes_to_add, true);
		}

		template<class T,class Alloc,size_t Bufsize>
		void deque<T, Alloc, Bufsize>::reallocate_map(size_type nodes_to_add,
			bool add_at_front) {
			size_type old_num_nodes = finish.node - start.node + 1;
			size_type new_num_nodes = old_num_nodes + nodes_to_add;

			map_pointer new_nstart;
			if (map_size > 2 * new_num_nodes) {
				//并未配置新空间,将数据前移或后移
				new_nstart = map + (map_size - new_num_nodes) / 2
					+ (add_at_front ? nodes_to_add : 0);
				if (new_nstart < start.node)
					copy(start.node, finish.node + 1, new_nstart);
				else
					copy_backward(start.node, finish.node_1, new_nstart + old_num_nodes);
			}
			else {
				size_type new_map_size = map_size + max(map_size, nodes_to_add + 2);
				//配置一块空间,准备给新map使用
				map_pointer new_map = map_allocator::allocate(new_map_size);
				new_nstart = new_map + (new_map_size - new_num_nodes) / 2
					+ (add_at_front ? nodes_to_add : 0);
				//把原map内容拷贝过来
				copy(start.node, finish.node + 1, new_nstart);
				//释放原map
				map_allocator::deallocate(map, map_size);
				//设定新map的起始地址与大小
				map = new_map;
				map_size = new_map_size;
			}
			//重新设定迭代器start和finish
			start.set_node(new_nstart);
			finish.set_node(new_nstart + old_num_nodes - 1);
		}

元素操作:pop_back,pop_front,clear,erase,insert

pop_back()和pop_front():

void pop_back() {
				if (finish.cur != finish.first) {
					//最后缓冲区有一个或更多元素
					--finish.cur;//调整指针,相当于排除了最后元素
					destroy(finish.cur);//将最后元素析构
				}
				else
					//最后缓冲区没有任何元素
					pop_back_aux();//这里将进行缓冲区的释放工作
				}

			//只有当finish.cur==finish.first时调用
			template<class T,class Alloc,size_t Bufsize>
			void deque<T, Alloc, Bufsize>::pop_back_aux() {
				deallocate_node(finish.first);//释放最后一个缓冲区
				finish.set_node(finish.node - 1);//调整finish的状态,使指向
				finish.cur = finish.last - 1;    //上一个缓冲区的最后一个元素
				destroy(finish.cur);             //将该元素析构
			}

			void pop_front() {
				if (start.cur != start.last - 1) {
					//第一缓冲区由两个或更多元素
					destroy(start.cur);//将第一元素析构
					++start.cur;//调整指针,相当于排除了第一元素
				}
				else
					//第一缓冲区仅有一个元素
					pop_front_aux();//进行缓冲区的释放工作
			}

			//只有当start.cur==start.last-1时才会被调用
			template<class T,class Alloc,size_t Bufsize>
			void deque<T, Alloc, Bufsize>::pop_front_aux() {
				destroy(start.cur);//将第一缓冲区的第一个(也是最后一个、唯一一个)元素析构
				deallocate_node(start.first);//释放第一缓冲区
				start.set_node(start.node + 1);//调整start的状态,使指向下一个缓冲区的第一个元素
				start.cur = start.first;
			}

clear():用于清除这个deque。deque的最初状态(无任何元素)保有一个缓冲区,因此,clear()完成之后回复初始状态,也保留一个缓冲区。

//最终需要保留一个缓冲区
				//这是deque的策略,也是其初始状态
				template<class T,class Alloc,size_t Bufsize>
				void deque<T, Alloc, Bufsize>::clear() {
					//以下针对头尾以外的每一个缓冲区,它们必定时饱满的
					for (map_pointer node = start.node + 1; node < finish.node; ++node) {
						//将缓冲区内的所有元素析构
						destroy(*node, *node + buffer_size());
						//释放缓冲区内存
						data_allocator::deallocate(*node, buffer_size());
					}

					if (start.node != finish.node) {
						//至少由头尾两个缓冲区
						destroy(start.cur, start.last);//将头缓冲区的所有元素析构
						destroy(finish.first, finish.cur);//将尾缓冲区的所有元素析构
						//以下释放尾缓冲区,头缓冲区保留
						data_allocator::deallocate(finish.first, buffer_size());
					}
					else//只有一个缓冲区
						destroy(start.cur, finish.cur);//将此唯一缓冲区内的所有元素析构
					//注意,并不释放缓冲区空间,这唯一的缓冲区将保留

					finish = start;//调整状态
				}

erase():用于清除某个元素或某个区间内的元素。

//清除pos所指的元素,pos为清除点
					iterator erase(iterator pos) {
						iterator next = pos;
						++next;
						difference_type index = pos - start;//清除点之前的元素个数
						if (index < (size() >> 1)) {//如果清除点之前的元素比较少
							copy_backward(start, pos, next);//移动清除点之前的元素
							pop_front();//移动完毕,清除最前一个元素
						}
						else {
							//清除点之后的元素比较少
							copy(next, finish, pos);//移动清除点之后的元素
							pop_back();//清除最后一个元素
						}
						return start + index;
					}

					//清除[first,last)区间内的元素
					template<class T,class Alloc,size_t Bufsize>
					deque<T,Alloc,Bufsize>::iterator
						deque<T, Alloc, Bufsize>::erase(iterator first, iterator last) {
						if (first == start&&last == finish) {
							//如果清除区间时整个deque,直接调用clear
							clear();
							return finish;
						}
						else {
							difference_type n = last - first;//清除区间长度
							difference_type elems_before = first - start;//清除区间前方的元素个数
							if (elems_before < (size() - n) / 2) {
								//如果清除区间前方的元素比较少
								copy_backward(start, first, last);//向后移动前方元素(覆盖清除区间)
								iterator new_start = start + n;//标记deque的新起点
								destroy(start, new_start);//移动完毕,将冗余元素析构
								//以下将冗余的缓冲区释放
								for (map_pointer cur = start.node; cur < new_start.node; ++cur)
									data_allocator::deallocate(*cur, buffer_size());
								start = new_start;//设定deque的新起点
							}
							else {
								//如果清除区间后方的元素比较少
								copy(last, finish, first);
								iterator new_finish = finish - n;
								destroy(new_finish, finish);
								//以下将冗余的缓冲区释放
								for (map_pointer cur = new_finish.node + 1; cur <= finish.node; ++cur)
									data_allocator::deallocate(*cur, buffer_size());
								finish = new_finish;
							}
							return start + elems_before;
						}
					}

insert():有多个版本,以下为最基础的版本,允许在某个点之前插入一个元素,并设定其值。

iterator insert(iterator position, const value_type& x) {
							if (position.cur == start.cur) {
								//如果插入点为deque最前端,交给push_front()
								push_front(x);
								return start;
							}
							else if (position.cur == finish.cur) {
								//如果插入点为deque最尾端,交给push_back()
								push_back(x);
								iterator tmp = finish;
								--tmp;
								return tmp;
							}
							else
								return insert_aux(position, x);
						}

						template<class T,class Alloc,size_t Bufsize>
						typename deque<T,Alloc,Bufsize>::iterator
							deque<T, Alloc, Bufsize>::insert_aux(iterator pos, const value_type& x) {
							difference_type index = pos - start;//插入点之前的元素个数
							value_type x_copy = x;
							if (index < size() / 2)
							{
								//如果插入点之前的元素个数比较少
								push_front(front());//在最前端加入与第一元素同值的元素
								iterator front1 = start;//以下标示记号,然后进行元素移动
								++front1;
								iterator front2 = front1;
								++front2;
								pos = start + index;
								iterator pos1 = pos;
								++pos1;
								copy(front2, pos1, front1);
							}
							else {
								push_back(back());
								iterator back1 = finish;
								--back1;
								iterator back2 = back1;
								--back2;
								pos = start + index;
								copy_backward(pos, back2, back1);
							}
							*pos = x_copy;
							return pos;
						}


 
 




猜你喜欢

转载自blog.csdn.net/s_hit/article/details/79503029