STL之deque(四)

	void push_back(const value_type& t)
	{
		// 最后缓冲区尚有两个(含)以上的元素备用空间
		if (finish.cur != finish.last - 1)
		{
			construct(finish.cur, t);     // 直接在备用空间上构造元素
			++finish.cur;     // 调整最后缓冲区的使用状态
		}
		// 容量已满就要新申请内存了
		else
			push_back_aux(t);
	}
// 只有当finish.cur == finish.last - 1 时才会被调用
// 也就是说,只有当最后一个缓冲区只剩下一个备用元素空间时才会被调用
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();
	*(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)));
}
 void reserve_map_at_back (size_type nodes_to_add = 1)
 {
        //  l= map + map_size ==最后的node之后一个越界的node
        //  l-finish.node -1 == 剩下的node个数
        //  nodes_to_add > l - finish.node -1 不需要重新分配内存
        if(nodes_to_add + 1 > map_size - (finish.node - map))
                    reallocate_map(nodes_to_add,false);//false表示在尾部重分配              
 }
//reallocate_map
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 ole_num_nodes = finish.node - start.node + 1;     
         size_type new_num_nodes = ole_num_nodes + nodes_to_add;
                       
         map_pointer new_nstart;//T**类型
                       
         if(map_size > 2 * new_num_nodes)
         {  
             //node内存数量是 两倍的 新的node数量 时调用, 头尾总是pop时,会剩余大量node
                    
             /*
                  最后要使头尾剩下的可分配(未使用)的node数量一样
                  如果add_at_front = true new_nstart会多一个node节点
                  如果add_at_front = false new_nfinish会多一个node节点
                     
                  说到底 这个reallocate函数并不添加node,他的使命是确保有足够的
                  nodes给前面的aux函数使用
             */
              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 + ole_num_nodes);
                    
          }
          else
          {         
               //剩下的没有两倍就 重新分配一块nodes内存
               //新的缓存区起码要留map_size+2 的大小
                size_type new_map_size = map_size + max(map_size, nodes_to_add) + 2;    
                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);
                    
                copy(start.node, finish,node +1, new_nstart);
                map_allocator::deallocate(map,map_size);
                    
                map=new_map;
                map_size = new_map_size;
                    
           }
                
           start.set_node(new_nstart);
           finish.set_node(new_nstart + ole_num_nodes);
                
 }
void push_front(const value_type& t)
{
       if (start.cur != start.first)      // 第一缓冲区尚有备用空间
       {
		construct(start.cur - 1, t);   // 直接在备用空间上构造元素
		--start.cur;     // 调整第一缓冲区的使用状态
	}
	else    // 第一缓冲区已无备用空间
		push_front_aux(t);
}
// Called only if start.cur == start.first.
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();
	*(start.node - 1) = allocate_node();
	__STL_TRY
	{
		start.set_node(start.node - 1);        // 改变start,令其指向新节点
		start.cur = start.last - 1;            // 设定start的状态
		construct(start.cur, t_copy);          // 针对标的元素设值
	}
	catch(...)
	{
		start.set_node(start.node + 1);
		start.cur = start.first;
		deallocate_node(*(start.node - 1));
		throw;
	}
}

        pop_back和pop_front函数讲解:

//pop_back
void pop_back()
{
        if(finish.cur != finish.first)
        {
              --finish.cur;
              destroy(finish.cur);
         }
         else
                    
               pop_back_aux();
                
 }
            
//pop_back_aux
template<class T,class Alloc,size_t BufSize>
void deque<T,Alloc,BufSize>::pop_back_aux()
{
        //释放finish的缓存,使finish指向前一个node末尾
        //deallocate_node(pointer n){ data_allocator::deallocate(n,buffer_size());}
        deallocate_node(finish.first);
        finish.set_node(finish.node - 1);
        finish.cur = finish.last -1;
        destroy(finish.cur);
}
            
//pop_front 
void pop_front()
{
        if(start.cur != start.last -1 )
        {
              destroy(start.cur)
              ++start.cur;
         }
         else      
              pop_front_aux();
}
         
//pop_front_aux
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.cur = start.first;
}

        clear函数讲解:

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函数讲解:

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;
}

        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);
          }
 }

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;
}
deque完结!
### C++ STL `deque` 使用方法及特性 #### 一、基本概念 `std::deque<T>` 是标准模板库(STL)提供的一种双端队列容器,支持快速的随机访问以及高效的两端插入和删除操作。这种灵活性使得它适用于多种场景下的数据存储需求。 #### 二、主要功能与使用方式 ##### (一)创建与初始化 可以像其他STL容器一样通过默认构造函数来实例化一个空的`deque`对象;也可以指定初始大小或填充特定数量相同类型的元素进行初始化[^4]。 ```cpp // 创建一个整型dequeue,默认无参数则为空 std::deque<int> myDeque; // 初始化含有五个零值整数的dequeue std::deque<int> anotherDeque(5, 0); ``` ##### (二)元素存取 提供了`front()`获取头部元素引用,`back()`获得尾部元素引用的方法。对于任意位置上的元素,则可以直接利用下标运算符[]来进行读写操作。 ```cpp myDeque.push_back(1); // 向后追加新项 anotherDeque.front(); // 访问第一个元素 anotherDeque.back(); // 获取最后一个元素 anotherDeque[2]; // 索引第三个元素 (假设存在) ``` ##### (三)增删改查 - 插入:除了常规的`push_back()/push_front()`外,在C++20版本之后还增加了更灵活的方式——`emplace_*`系列成员函数允许直接在目标地点构建对象而无需先创建临时变量再转移所有权[^3]; - 删除:不仅能够分别针对前后两端调用`pop_back()/pop_front()`移除单个节点,还可以借助于新增API如`erase_if()`批量清除符合条件的所有条目[^1]; - 修改:可通过迭代器配合算法库中的工具完成复杂变换任务,比如下面的例子展示了如何将每一个数值翻倍处理[^2]: ```cpp std::for_each(myDeque.begin(), myDeque.end(), [](int& elem){ elem *= 2; }); ``` ##### ()查询统计 为了方便开发者判断当前状态,内置了一些辅助性的属性接口,例如检测是否为空(`empty()`)或是计算总长度(`size()`). #### 三、内部结构特点分析 不同于连续内存布局的传统数组向量(vector),`deque`采用了分段式的管理策略,即将整个序列分割成若干固定大小的小块(block),每一块之间保持一定间隔以便后续扩展时能更容易找到合适的位置安插新的片段而不至于频繁触发大规模重定位动作。这样的设计既保留了一定程度上类似于链表那样动态调整的优势,又兼顾到了接近线性寻址所带来的性能提升效果. #### 、适用范围对比总结 当面对需要频繁执行双向末端更新且偶尔涉及中间部分修改的应用场合时,选用`deque`往往可以获得更好的综合表现。然而值得注意的是由于其特殊的组织形式可能会造成缓存命中率下降进而影响到某些情况下顺序扫描效率,所以在实际项目选型过程中应当权衡利弊做出合理抉择.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值